17
17
# Icons modified from
18
18
# https://github.com/matplotlib/matplotlib/tree/main/lib/matplotlib/mpl-data/images
19
19
ICON_ROOT = Path (__file__ ).parent / "icons"
20
- __all__ = ["NapariMPLWidget" ]
20
+ __all__ = ["MPLWidget" , " NapariMPLWidget" ]
21
21
22
22
23
- class NapariMPLWidget (QWidget ):
23
+ class MPLWidget (QWidget ):
24
24
"""
25
25
Widget containing a Matplotlib canvas and toolbar.
26
26
@@ -47,12 +47,10 @@ class NapariMPLWidget(QWidget):
47
47
48
48
def __init__ (
49
49
self ,
50
- napari_viewer : napari .viewer .Viewer ,
51
50
parent : Optional [QWidget ] = None ,
52
51
):
53
52
super ().__init__ (parent = parent )
54
53
55
- self .viewer = napari_viewer
56
54
self .canvas = FigureCanvas ()
57
55
58
56
self .canvas .figure .patch .set_facecolor ("none" )
@@ -66,6 +64,87 @@ def __init__(
66
64
self .layout ().addWidget (self .toolbar )
67
65
self .layout ().addWidget (self .canvas )
68
66
67
+ @property
68
+ def figure (self ) -> Figure :
69
+ """Matplotlib figure."""
70
+ return self .canvas .figure
71
+
72
+ def add_single_axes (self ) -> None :
73
+ """
74
+ Add a single Axes to the figure.
75
+
76
+ The Axes is saved on the ``.axes`` attribute for later access.
77
+ """
78
+ self .axes = self .figure .subplots ()
79
+ self .apply_napari_colorscheme (self .axes )
80
+
81
+ @staticmethod
82
+ def apply_napari_colorscheme (ax : Axes ) -> None :
83
+ """Apply napari-compatible colorscheme to an Axes."""
84
+ # changing color of axes background to transparent
85
+ ax .set_facecolor ("none" )
86
+
87
+ # changing colors of all axes
88
+ for spine in ax .spines :
89
+ ax .spines [spine ].set_color ("white" )
90
+
91
+ ax .xaxis .label .set_color ("white" )
92
+ ax .yaxis .label .set_color ("white" )
93
+
94
+ # changing colors of axes labels
95
+ ax .tick_params (axis = "x" , colors = "white" )
96
+ ax .tick_params (axis = "y" , colors = "white" )
97
+
98
+ def _replace_toolbar_icons (self ) -> None :
99
+ # Modify toolbar icons and some tooltips
100
+ for action in self .toolbar .actions ():
101
+ text = action .text ()
102
+ if text == "Pan" :
103
+ action .setToolTip (
104
+ "Pan/Zoom: Left button pans; Right button zooms; "
105
+ "Click once to activate; Click again to deactivate"
106
+ )
107
+ if text == "Zoom" :
108
+ action .setToolTip (
109
+ "Zoom to rectangle; Click once to activate; "
110
+ "Click again to deactivate"
111
+ )
112
+ if len (text ) > 0 : # i.e. not a separator item
113
+ icon_path = os .path .join (ICON_ROOT , text + ".png" )
114
+ action .setIcon (QIcon (icon_path ))
115
+
116
+
117
+ class NapariMPLWidget (MPLWidget ):
118
+ """
119
+ Widget containing a Matplotlib canvas and toolbar.
120
+
121
+ In addition to `BaseNapariMPLWidget`, this class handles callbacks
122
+ to automatically update figures when the layer selection or z-step
123
+ is changed in the napari viewer. To take advantage of this sub-classes
124
+ should implement the ``clear()`` and ``draw()`` methods.
125
+
126
+ When both the z-step and layer selection is changed, ``clear()`` is called
127
+ and if the number a type of selected layers are valid for the widget
128
+ ``draw()`` is then called. When layer selection is changed ``on_update_layers()``
129
+ is also called, which can be useful e.g. for updating a layer list in a
130
+ selection widget.
131
+
132
+ Attributes
133
+ ----------
134
+ viewer : `napari.Viewer`
135
+ Main napari viewer.
136
+ layers : `list`
137
+ List of currently selected napari layers.
138
+ """
139
+
140
+ def __init__ (
141
+ self ,
142
+ napari_viewer : napari .viewer .Viewer ,
143
+ parent : Optional [QWidget ] = None ,
144
+ ):
145
+ super ().__init__ (parent = parent )
146
+
147
+ self .viewer = napari_viewer
69
148
self ._setup_callbacks ()
70
149
self .layers : List [napari .layers .Layer ] = []
71
150
@@ -74,11 +153,6 @@ def __init__(
74
153
#: Type of layer taken as input
75
154
input_layer_types : Tuple [napari .layers .Layer , ...] = (napari .layers .Layer ,)
76
155
77
- @property
78
- def figure (self ) -> Figure :
79
- """Matplotlib figure."""
80
- return self .canvas .figure
81
-
82
156
@property
83
157
def n_selected_layers (self ) -> int :
84
158
"""
@@ -104,14 +178,16 @@ def _setup_callbacks(self) -> None:
104
178
# z-step changed in viewer
105
179
self .viewer .dims .events .current_step .connect (self ._draw )
106
180
# Layer selection changed in viewer
107
- self .viewer .layers .selection .events .changed .connect (self .update_layers )
181
+ self .viewer .layers .selection .events .changed .connect (
182
+ self ._update_layers
183
+ )
108
184
109
- def update_layers (self , event : napari .utils .events .Event ) -> None :
185
+ def _update_layers (self , event : napari .utils .events .Event ) -> None :
110
186
"""
111
187
Update the ``layers`` attribute with currently selected layers and re-draw.
112
188
"""
113
189
self .layers = list (self .viewer .layers .selection )
114
- self ._on_update_layers ()
190
+ self .on_update_layers ()
115
191
self ._draw ()
116
192
117
193
def _draw (self ) -> None :
@@ -140,58 +216,13 @@ def draw(self) -> None:
140
216
This is a no-op, and is intended for derived classes to override.
141
217
"""
142
218
143
- def add_single_axes (self ) -> None :
144
- """
145
- Add a single Axes to the figure.
146
-
147
- The Axes is saved on the ``.axes`` attribute for later access.
219
+ def on_update_layers (self ) -> None :
148
220
"""
149
- self .axes = self .figure .subplots ()
150
- self .apply_napari_colorscheme (self .axes )
151
-
152
- @staticmethod
153
- def apply_napari_colorscheme (ax : Axes ) -> None :
154
- """Apply napari-compatible colorscheme to an Axes."""
155
- # changing color of axes background to transparent
156
- ax .set_facecolor ("none" )
157
-
158
- # changing colors of all axes
159
- for spine in ax .spines :
160
- ax .spines [spine ].set_color ("white" )
161
-
162
- ax .xaxis .label .set_color ("white" )
163
- ax .yaxis .label .set_color ("white" )
164
-
165
- # changing colors of axes labels
166
- ax .tick_params (axis = "x" , colors = "white" )
167
- ax .tick_params (axis = "y" , colors = "white" )
168
-
169
- def _on_update_layers (self ) -> None :
170
- """
171
- Function is called when self.layers is updated via
172
- ``self.update_layers()``.
221
+ Called when the selected layers are updated.
173
222
174
223
This is a no-op, and is intended for derived classes to override.
175
224
"""
176
225
177
- def _replace_toolbar_icons (self ) -> None :
178
- # Modify toolbar icons and some tooltips
179
- for action in self .toolbar .actions ():
180
- text = action .text ()
181
- if text == "Pan" :
182
- action .setToolTip (
183
- "Pan/Zoom: Left button pans; Right button zooms; "
184
- "Click once to activate; Click again to deactivate"
185
- )
186
- if text == "Zoom" :
187
- action .setToolTip (
188
- "Zoom to rectangle; Click once to activate; "
189
- "Click again to deactivate"
190
- )
191
- if len (text ) > 0 : # i.e. not a separator item
192
- icon_path = os .path .join (ICON_ROOT , text + ".png" )
193
- action .setIcon (QIcon (icon_path ))
194
-
195
226
196
227
class NapariNavigationToolbar (NavigationToolbar2QT ):
197
228
"""Custom Toolbar style for Napari."""
0 commit comments