Skip to content

Commit c481207

Browse files
authored
Merge pull request #237 from Chris-N-K/theme_detection_update
Theme detection and update improvements
2 parents cf1b129 + 2d1f804 commit c481207

20 files changed

+87
-167
lines changed

MANIFEST.in

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
include LICENSE
22
include README.md
3-
recursive-include * *.mplstyle
43

54
recursive-exclude * __pycache__
65
recursive-exclude * *.py[co]

docs/user_guide.rst

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,6 @@ To use these:
4040

4141
Customising plots
4242
-----------------
43-
`Matplotlib style sheets <https://matplotlib.org/stable/tutorials/introductory/customizing.html#defining-your-own-style>`__ can be used to customise
44-
the plots generated by ``napari-matplotlib``.
45-
To use a custom style sheet:
46-
47-
1. Save it as ``napari-matplotlib.mplstyle``
48-
2. Put it in the Matplotlib configuration directory.
49-
The location of this directory varies on different computers,
50-
and can be found by calling :func:`matplotlib.get_configdir()`.
43+
``napari-matplotlib`` uses colours from the current napari theme to customise the
44+
Matplotlib plots. See `the example on creating a new napari theme
45+
<https://napari.org/stable/gallery/new_theme.html>`_ for a helpful guide.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ write_to = "src/napari_matplotlib/_version.py"
77

88
[tool.pytest.ini_options]
99
qt_api = "pyqt6"
10-
addopts = "--mpl"
10+
addopts = "--mpl --mpl-baseline-relative"
1111
filterwarnings = [
1212
"error",
1313
# Coming from vispy

src/napari_matplotlib/base.py

Lines changed: 35 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,22 @@
22
from pathlib import Path
33
from typing import Optional
44

5-
import matplotlib
65
import matplotlib.style as mplstyle
76
import napari
87
from matplotlib.backends.backend_qtagg import ( # type: ignore[attr-defined]
98
FigureCanvasQTAgg,
109
NavigationToolbar2QT,
1110
)
1211
from matplotlib.figure import Figure
12+
from napari.utils.events import Event
13+
from napari.utils.theme import get_theme
1314
from qtpy.QtGui import QIcon
1415
from qtpy.QtWidgets import QLabel, QVBoxLayout, QWidget
1516

16-
from .util import Interval, from_napari_css_get_size_of
17+
from .util import Interval, from_napari_css_get_size_of, style_sheet_from_theme
1718

1819
__all__ = ["BaseNapariMPLWidget", "NapariMPLWidget", "SingleAxesWidget"]
1920

20-
_CUSTOM_STYLE_PATH = (
21-
Path(matplotlib.get_configdir()) / "napari-matplotlib.mplstyle"
22-
)
23-
2421

2522
class BaseNapariMPLWidget(QWidget):
2623
"""
@@ -45,18 +42,17 @@ def __init__(
4542
):
4643
super().__init__(parent=parent)
4744
self.viewer = napari_viewer
48-
self._mpl_style_sheet_path: Optional[Path] = None
45+
self.napari_theme_style_sheet = style_sheet_from_theme(
46+
get_theme(napari_viewer.theme, as_dict=False)
47+
)
4948

5049
# Sets figure.* style
51-
with mplstyle.context(self.mpl_style_sheet_path):
50+
with mplstyle.context(self.napari_theme_style_sheet):
5251
self.canvas = FigureCanvasQTAgg() # type: ignore[no-untyped-call]
5352

5453
self.canvas.figure.set_layout_engine("constrained")
5554
self.toolbar = NapariNavigationToolbar(self.canvas, parent=self)
5655
self._replace_toolbar_icons()
57-
# callback to update when napari theme changed
58-
# TODO: this isn't working completely (see issue #140)
59-
# most of our styling respects the theme change but not all
6056
self.viewer.events.theme.connect(self._on_napari_theme_changed)
6157

6258
self.setLayout(QVBoxLayout())
@@ -68,24 +64,6 @@ def figure(self) -> Figure:
6864
"""Matplotlib figure."""
6965
return self.canvas.figure
7066

71-
@property
72-
def mpl_style_sheet_path(self) -> Path:
73-
"""
74-
Path to the set Matplotlib style sheet.
75-
"""
76-
if self._mpl_style_sheet_path is not None:
77-
return self._mpl_style_sheet_path
78-
elif (_CUSTOM_STYLE_PATH).exists():
79-
return _CUSTOM_STYLE_PATH
80-
elif self._napari_theme_has_light_bg():
81-
return Path(__file__).parent / "styles" / "light.mplstyle"
82-
else:
83-
return Path(__file__).parent / "styles" / "dark.mplstyle"
84-
85-
@mpl_style_sheet_path.setter
86-
def mpl_style_sheet_path(self, path: Path) -> None:
87-
self._mpl_style_sheet_path = Path(path)
88-
8967
def add_single_axes(self) -> None:
9068
"""
9169
Add a single Axes to the figure.
@@ -94,13 +72,21 @@ def add_single_axes(self) -> None:
9472
"""
9573
# Sets axes.* style.
9674
# Does not set any text styling set by axes.* keys
97-
with mplstyle.context(self.mpl_style_sheet_path):
75+
with mplstyle.context(self.napari_theme_style_sheet):
9876
self.axes = self.figure.add_subplot()
9977

100-
def _on_napari_theme_changed(self) -> None:
78+
def _on_napari_theme_changed(self, event: Event) -> None:
10179
"""
10280
Called when the napari theme is changed.
81+
82+
Parameters
83+
----------
84+
event : napari.utils.events.Event
85+
Event that triggered the callback.
10386
"""
87+
self.napari_theme_style_sheet = style_sheet_from_theme(
88+
get_theme(event.value, as_dict=False)
89+
)
10490
self._replace_toolbar_icons()
10591

10692
def _napari_theme_has_light_bg(self) -> bool:
@@ -211,15 +197,18 @@ def current_z(self) -> int:
211197
"""
212198
return self.viewer.dims.current_step[0]
213199

214-
def _on_napari_theme_changed(self) -> None:
200+
def _on_napari_theme_changed(self, event: Event) -> None:
215201
"""Update MPL toolbar and axis styling when `napari.Viewer.theme` is changed.
216202
217-
Note:
218-
At the moment we only handle the default 'light' and 'dark' napari themes.
203+
Parameters
204+
----------
205+
event : napari.utils.events.Event
206+
Event that triggered the callback.
219207
"""
220-
super()._on_napari_theme_changed()
221-
self.clear()
222-
self.draw()
208+
super()._on_napari_theme_changed(event)
209+
# use self._draw instead of self.draw to cope with redraw while there are no
210+
# layers, this makes the self.clear() obsolete
211+
self._draw()
223212

224213
def _setup_callbacks(self) -> None:
225214
"""
@@ -252,13 +241,15 @@ def _draw(self) -> None:
252241
"""
253242
# Clearing axes sets new defaults, so need to make sure style is applied when
254243
# this happens
255-
with mplstyle.context(self.mpl_style_sheet_path):
244+
with mplstyle.context(self.napari_theme_style_sheet):
245+
# everything should be done in the style context
256246
self.clear()
257-
if self.n_selected_layers in self.n_layers_input and all(
258-
isinstance(layer, self.input_layer_types) for layer in self.layers
259-
):
260-
self.draw()
261-
self.canvas.draw() # type: ignore[no-untyped-call]
247+
if self.n_selected_layers in self.n_layers_input and all(
248+
isinstance(layer, self.input_layer_types)
249+
for layer in self.layers
250+
):
251+
self.draw()
252+
self.canvas.draw() # type: ignore[no-untyped-call]
262253

263254
def clear(self) -> None:
264255
"""
@@ -300,7 +291,7 @@ def clear(self) -> None:
300291
"""
301292
Clear the axes.
302293
"""
303-
with mplstyle.context(self.mpl_style_sheet_path):
294+
with mplstyle.context(self.napari_theme_style_sheet):
304295
self.axes.clear()
305296

306297

src/napari_matplotlib/styles/README.md

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/napari_matplotlib/styles/dark.mplstyle

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/napari_matplotlib/styles/light.mplstyle

Lines changed: 0 additions & 12 deletions
This file was deleted.
Loading

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy