8000 Merge pull request #125 from dstansby/refactor · melissawm/napari-matplotlib@20bc846 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 20bc846

Browse files
authored
Merge pull request matplotlib#125 from dstansby/refactor
Factor out layer selecton and MPL figure creation
2 parents 51b6b03 + 0e2f047 commit 20bc846

File tree

2 files changed

+82
-67
lines changed

2 files changed

+82
-67
lines changed

docs/changelog.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ Changelog
44
0.3.0
55
-----
66

7+
New features
8+
~~~~~~~~~~~~
9+
- Added `MPLWidget` as a widget containing just a Matplotlib canvas
10+
without any association with a napari viewer.
11+
712
Visual improvements
813
~~~~~~~~~~~~~~~~~~~
914
- The background of ``napari-matplotlib`` figures and axes is now transparent.

src/napari_matplotlib/base.py

Lines changed: 77 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -17,41 +17,25 @@
1717
# Icons modified from
1818
# https://github.com/matplotlib/matplotlib/tree/main/lib/matplotlib/mpl-data/images
1919
ICON_ROOT = Path(__file__).parent / "icons"
20-
__all__ = ["NapariMPLWidget"]
20+
__all__ = ["MPLWidget", "NapariMPLWidget"]
2121

2222

23-
class NapariMPLWidget(QWidget):
23+
class MPLWidget(QWidget):
2424
"""
2525
Widget containing a Matplotlib canvas and toolbar.
2626
2727
This creates a single FigureCanvas, which contains a single
2828
`~matplotlib.figure.Figure`, and an associated toolbar.
2929
It is not responsible for creating any Axes, because different
3030
widgets may want to implement different subplot layouts.
31-
32-
This class also handles callbacks to automatically update figures when
33-
the layer selection or z-step is changed in the napari viewer. To take
34-
advantage of this sub-classes should implement the ``clear()`` and
35-
``draw()`` methods.
36-
37-
Attributes
38-
----------
39-
viewer : `napari.Viewer`
40-
Main napari viewer.
41-
canvas : matplotlib.backends.backend_qt5agg.FigureCanvas
42-
Matplotlib canvas.
43-
layers : `list`
44-
List of currently selected napari layers.
4531
"""
4632

4733
def __init__(
4834
self,
49-
napari_viewer: napari.viewer.Viewer,
5035
parent: Optional[QWidget] = None,
5136
):
5237
super().__init__(parent=parent)
5338

54-
self.viewer = napari_viewer
5539
self.canvas = FigureCanvas()
5640

5741
self.canvas.figure.patch.set_facecolor("none")
@@ -65,6 +49,81 @@ def __init__(
6549
self.layout().addWidget(self.toolbar)
6650
self.layout().addWidget(self.canvas)
6751

52+
@property
53+
def figure(self) -> Figure:
54+
"""Matplotlib figure."""
55+
return self.canvas.figure
56+
57+
def add_single_axes(self) -> None:
58+
"""
59+
Add a single Axes to the figure.
60+
61+
The Axes is saved on the ``.axes`` attribute for later access.
62+
"""
63+
self.axes = self.figure.subplots()
64+
self.apply_napari_colorscheme(self.axes)
65+
66+
@staticmethod
67+
def apply_napari_colorscheme(ax: Axes) -> None:
68+
"""Apply napari-compatible colorscheme to an Axes."""
69+
# changing color of axes background to transparent
70+
ax.set_facecolor("none")
71+
72+
# changing colors of all axes
73+
for spine in ax.spines:
74+
ax.spines[spine].set_color("white")
75+
76+
ax.xaxis.label.set_color("white")
77+
ax.yaxis.label.set_color("white")
78+
79+
# changing colors of axes labels
80+
ax.tick_params(axis="x", colors="white")
81+
ax.tick_params(axis="y", colors="white")
82+
83+
def _replace_toolbar_icons(self) -> None:
84+
# Modify toolbar icons and some tooltips
85+
for action in self.toolbar.actions():
86+
text = action.text()
87+
if text == "Pan":
88+
action.setToolTip(
89+
"Pan/Zoom: Left button pans; Right button zooms; "
90+
"Click once to activate; Click again to deactivate"
91+
)
92+
if text == "Zoom":
93+
action.setToolTip(
94+
"Zoom to rectangle; Click once to activate; "
95+
"Click again to deactivate"
96+
)
97+
if len(text) > 0: # i.e. not a separator item
98+
icon_path = os.path.join(ICON_ROOT, text + ".png")
99+
action.setIcon(QIcon(icon_path))
100+
101+
102+
class NapariMPLWidget(MPLWidget):
103+
"""
104+
Widget containing a Matplotlib canvas and toolbar.
105+
106+
In addition to `BaseNapariMPLWidget`, this class handles callbacks
107+
to automatically update figures when the layer selection or z-step
108+
is changed in the napari viewer. To take advantage of this sub-classes
109+
should implement the ``clear()`` and ``draw()`` methods.
110+
111+
Attributes
112+
----------
113+
viewer : `napari.Viewer`
114+
Main napari viewer.
115+
layers : `list`
116+
List of currently selected napari layers.
117+
"""
118+
119+
def __init__(
120+
self,
121+
napari_viewer: napari.viewer.Viewer,
122+
parent: Optional[QWidget] = None,
123+
):
124+
super().__init__(parent=parent)
125+
126+
self.viewer = napari_viewer
68127
self._setup_callbacks()
69128
self.layers: List[napari.layers.Layer] = []
70129

@@ -73,11 +132,6 @@ def __init__(
73132
#: Type of layer taken as input
74133
input_layer_types: Tuple[napari.layers.Layer, ...] = (napari.layers.Layer,)
75134

76-
@property
77-
def figure(self) -> Figure:
78-
"""Matplotlib figure."""
79-
return self.canvas.figure
80-
81135
@property
82136
def n_selected_layers(self) -> int:
83137
"""
@@ -139,32 +193,6 @@ def draw(self) -> None:
139193
This is a no-op, and is intended for derived classes to override.
140194
"""
141195

142-
def add_single_axes(self) -> None:
143-
"""
144-
Add a single Axes to the figure.
145-
146-
The Axes is saved on the ``.axes`` attribute for later access.
147-
"""
148-
self.axes = self.figure.subplots()
149-
self.apply_napari_colorscheme(self.axes)
150-
151-
@staticmethod
152-
def apply_napari_colorscheme(ax: Axes) -> None:
153-
"""Apply napari-compatible colorscheme to an Axes."""
154-
# changing color of axes background to transparent
155-
ax.set_facecolor("none")
156-
157-
# changing colors of all axes
158-
for spine in ax.spines:
159-
ax.spines[spine].set_color("white")
160-
161-
ax.xaxis.label.set_color("white")
162-
ax.yaxis.label.set_color("white")
163-
164-
# changing colors of axes labels
165-
ax.tick_params(axis="x", colors="white")
166-
ax.tick_params(axis="y", colors="white")
167-
168196
def _on_update_layers(self) -> None:
169197
"""
170198
Function is called when self.layers is updated via
@@ -173,24 +201,6 @@ def _on_update_layers(self) -> None:
173201
This is a no-op, and is intended for derived classes to override.
174202
"""
175203

176-
def _replace_toolbar_icons(self) -> None:
177-
# Modify toolbar icons and some tooltips
178-
for action in self.toolbar.actions():
179-
text = action.text()
180-
if text == "Pan":
181-
action.setToolTip(
182-
"Pan/Zoom: Left button pans; Right button zooms; "
183-
"Click once to activate; Click again to deactivate"
184-
)
185-
if text == "Zoom":
186-
action.setToolTip(
187-
"Zoom to rectangle; Click once to activate; "
188-
"Click again to deactivate"
189-
)
190-
if len(text) > 0: # i.e. not a separator item
191-
icon_path = os.path.join(ICON_ROOT, text + ".png")
192-
action.setIcon(QIcon(icon_path))
193-
194204

195205
class NapariNavigationToolbar(NavigationToolbar2QT):
196206
"""Custom Toolbar style for Napari."""

0 commit comments

Comments
 (0)
0