Skip to content

Commit

Permalink
set_theme() should accept feature_list (#1078)
Browse files Browse the repository at this point in the history
* Set multiple themes and flavors

* Add test for gggrid()

* Set theme in global variable.
  • Loading branch information
RYangazov committed Apr 15, 2024
1 parent e7a6e0d commit 0b34814
Show file tree
Hide file tree
Showing 8 changed files with 921 additions and 24 deletions.
855 changes: 855 additions & 0 deletions docs/dev/notebooks/set_multiple_themes.ipynb

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion future_changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,5 @@
- Add `linetype` parameter in `elementLine()` and `elementRect()` [[LPK-235](https://github.com/JetBrains/lets-plot-kotlin/issues/235)].
- Any way to line-wrap facet labels? [[LPK-237](https://github.com/JetBrains/lets-plot-kotlin/issues/237)].
- Missing marginal gridlines.
- Cryptic error message on geom_boxplot with orientation="y" [[#600](https://github.com/JetBrains/lets-plot/issues/600)].
- Cryptic error message on geom_boxplot with orientation="y" [[#600](https://github.com/JetBrains/lets-plot/issues/600)].
- `set_theme()` should accept "feature list" [[#657](https://github.com/JetBrains/lets-plot/issues/657)].
20 changes: 9 additions & 11 deletions python-package/lets_plot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@
# Copyright (c) 2019. JetBrains s.r.o.
# Use of this source code is governed by the MIT license that can be found in the LICENSE file.
#
import json
from pkgutil import extend_path
from typing import Dict
from typing import Dict, Union

# To handle the situation when the 'lets_plot' package is shared by modules in different locations.
__path__ = extend_path(__path__, __name__)

from ._version import __version__
from ._global_settings import _settings, is_production, get_global_bool, PLOT_THEME
from ._global_settings import _settings, is_production, get_global_bool
from ._global_settings import NO_JS, OFFLINE

from .plot import *
from .export import *
from .frontend_context import *
from .settings_utils import *
from .plot._global_theme import _set_global_theme

__all__ = (plot.__all__ +
frontend_context.__all__ +
Expand Down Expand Up @@ -161,22 +161,20 @@ def set(cls, settings: Dict):
_settings.update({'dev_' + key: value for key, value in settings.items()})

@classmethod
def set_theme(cls, theme: 'plot.FeatureSpec'):
def set_theme(cls, theme: Union['core.FeatureSpec', 'core.FeatureSpecArray']):
"""
Set up global theme.
Parameters
----------
theme : spec
Theme spec provided by `theme(...)` or `theme_xxx()` functions.
Theme spec provided by `theme(...)`, `theme_xxx()`, `flavor_xxx()` functions, or their sum.
"""
if theme.kind != 'theme':
raise ValueError("Wrong option type. Expected `theme` but was `{}`.".format(theme.kind))
if theme.kind != 'theme' and not (theme.kind == 'feature-list' and all(f.kind == 'theme' for f in theme)):
raise ValueError("Only `theme(...)`, `theme_xxx()`, `flavor_xxx()`, or a sum of them are supported")

LetsPlot.set({
PLOT_THEME: json.dumps(theme.as_dict())
})
_set_global_theme(theme)

@classmethod
def setup_show_ext(cls, *,
Expand Down Expand Up @@ -276,4 +274,4 @@ def setup_show_ext(cls, *,
p.show()
"""
cfg._setup_wb_html_context(exec=exec, new=new)
cfg._setup_wb_html_context(exec=exec, new=new)
1 change: 0 additions & 1 deletion python-package/lets_plot/_global_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
JS_URL_MANUAL = 'js_url_manual'
MAX_WIDTH = 'max_width'
MAX_HEIGHT = 'max_height'
PLOT_THEME = 'plot_theme'

MAPTILES_KIND = 'maptiles_kind'
MAPTILES_URL = 'maptiles_url'
Expand Down
14 changes: 14 additions & 0 deletions python-package/lets_plot/plot/_global_theme.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#
# Copyright (c) 2024. JetBrains s.r.o.
# Use of this source code is governed by the MIT license that can be found in the LICENSE file.
#
_global_theme = None


def _set_global_theme(theme):
global _global_theme
_global_theme = theme


def _get_global_theme():
return _global_theme
8 changes: 3 additions & 5 deletions python-package/lets_plot/plot/gggrid_.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
# Copyright (c) 2023. JetBrains s.r.o.
# Use of this source code is governed by the MIT license that can be found in the LICENSE file.
#
import json

from lets_plot._global_settings import has_global_value, get_global_val, PLOT_THEME
from lets_plot.plot.core import FeatureSpec, PlotSpec
from .subplots import SupPlotsLayoutSpec
from .subplots import SupPlotsSpec
from ._global_theme import _get_global_theme

__all__ = ['gggrid']

Expand Down Expand Up @@ -116,7 +115,7 @@ def gggrid(plots: list, ncol: int = None, *,
)

# Global Theme
global_theme_options = json.loads(get_global_val(PLOT_THEME)) if has_global_value(PLOT_THEME) else None
global_theme_options = _get_global_theme()

def _strip_theme_if_global(fig):
# Strip global theme options from plots in grid (see issue: #966).
Expand All @@ -136,7 +135,6 @@ def _strip_theme_if_global(fig):
figure_spec = SupPlotsSpec(figures=figures, layout=layout)

if global_theme_options is not None:
theme_name = global_theme_options.pop('name', None)
figure_spec += FeatureSpec('theme', theme_name, **global_theme_options)
figure_spec += global_theme_options

return figure_spec
10 changes: 4 additions & 6 deletions python-package/lets_plot/plot/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
# Copyright (c) 2019. JetBrains s.r.o.
# Use of this source code is governed by the MIT license that can be found in the LICENSE file.
#
import json
import numbers

from lets_plot._global_settings import has_global_value, get_global_val, MAX_WIDTH, MAX_HEIGHT, PLOT_THEME
from lets_plot._global_settings import has_global_value, get_global_val, MAX_WIDTH, MAX_HEIGHT
from lets_plot.geo_data_internals.utils import is_geocoder
from lets_plot.plot.core import FeatureSpec
from lets_plot.plot.core import PlotSpec
from lets_plot.plot.util import as_annotated_data
from lets_plot.plot._global_theme import _get_global_theme

__all__ = ['ggplot', 'ggsize', 'GGBunch']

Expand Down Expand Up @@ -87,10 +87,8 @@ def ggplot(data=None, mapping=None):

plot_spec = PlotSpec(data, mapping, scales=[], layers=[], **data_meta)

if has_global_value(PLOT_THEME):
theme_options = json.loads(get_global_val(PLOT_THEME))
theme_name = theme_options.pop('name', None)
plot_spec += FeatureSpec('theme', theme_name, **theme_options)
if _get_global_theme() is not None:
plot_spec += _get_global_theme()

return plot_spec

Expand Down
34 changes: 34 additions & 0 deletions python-package/test/plot/test_theme.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def test_plot_theme_element_values_merged():
assert 'b' == rect['fill']
assert 1 == rect['size']


def test_gggrid_theme_element_values_merged():
spec = (gg.gggrid(plots=[gg.ggplot() + _geom('foo')])
+ theme(panel_background=element_rect(color='a', fill='b'))
Expand Down Expand Up @@ -93,6 +94,39 @@ def test_global_theme_overriding():
assert 'top' == spec.as_dict()['theme']['legend_position']


def test_global_theme_feature_add():
gg.LetsPlot.set_theme(
theme_classic() + flavor_darcula() + theme(legend_position='bottom')
)

spec = gg.ggplot() + _geom('foo')
expected_theme = {
'name': 'classic',
'flavor': 'darcula',
'legend_position': 'bottom'
}

assert expected_theme == spec.as_dict()['theme']


def test_global_theme_feature_add_for_gggrid():
gg.LetsPlot.set_theme(
theme_classic() + flavor_darcula() + theme(legend_position='bottom')
)

spec_foo = gg.ggplot() + _geom('foo')
spec_bar = gg.ggplot() + _geom('bar')
spec = gg.gggrid([spec_foo, spec_bar])

expected_theme = {
'name': 'classic',
'flavor': 'darcula',
'legend_position': 'bottom'
}

assert expected_theme == spec.as_dict()['theme']


def test_overriding_global_named_theme():
gg.LetsPlot.set_theme(
theme_classic()
Expand Down

0 comments on commit 0b34814

Please sign in to comment.