1717# Icons modified from
1818# https://github.com/matplotlib/matplotlib/tree/main/lib/matplotlib/mpl-data/images
1919ICON_ROOT = Path (__file__ ).parent / "icons"
20- __all__ = ["NapariMPLWidget" ]
20+ __all__ = ["MPLWidget" , " NapariMPLWidget" ]
2121
2222
23- class NapariMPLWidget (QWidget ):
24- """Widget containing a Matplotlib canvas and toolbar.
23+ class MPLWidget (QWidget ):
24+ """
25+ Widget containing a Matplotlib canvas and toolbar.
2526
2627 This creates a single FigureCanvas, which contains a single
2728 `~matplotlib.figure.Figure`, and an associated toolbar.
2829 It is not responsible for creating any Axes, because different
2930 widgets may want to implement different subplot layouts.
30-
31- This class also handles callbacks to automatically update figures when
32- the layer selection or z-step is changed in the napari viewer. To take
33- advantage of this sub-classes should implement the ``clear()`` and
34- ``draw()`` methods.
35-
36- Attributes
37- ----------
38- viewer : `napari.Viewer`
39- Main napari viewer.
40- canvas : matplotlib.backends.backend_qt5agg.FigureCanvas
41- Matplotlib canvas.
42- layers : `list`
43- List of currently selected napari layers.
4431 """
4532
4633 def __init__ (
4734 self ,
48- napari_viewer : napari .viewer .Viewer ,
4935 parent : Optional [QWidget ] = None ,
5036 ):
5137 super ().__init__ (parent = parent )
5238
53- self .viewer = napari_viewer
5439 self .canvas = FigureCanvas ()
5540
5641 self .canvas .figure .patch .set_facecolor ("none" )
@@ -64,6 +49,87 @@ def __init__(
6449 self .layout ().addWidget (self .toolbar )
6550 self .layout ().addWidget (self .canvas )
6651
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+ When both the z-step and layer selection is changed, ``clear()`` is called
112+ and if the number a type of selected layers are valid for the widget
113+ ``draw()`` is then called. When layer selection is changed ``on_update_layers()``
114+ is also called, which can be useful e.g. for updating a layer list in a
115+ selection widget.
116+
117+ Attributes
118+ ----------
119+ viewer : `napari.Viewer`
120+ Main napari viewer.
121+ layers : `list`
122+ List of currently selected napari layers.
123+ """
124+
125+ def __init__ (
126+ self ,
127+ napari_viewer : napari .viewer .Viewer ,
128+ parent : Optional [QWidget ] = None ,
129+ ):
130+ super ().__init__ (parent = parent )
131+
132+ self .viewer = napari_viewer
67133 self ._setup_callbacks ()
68134 self .layers : List [napari .layers .Layer ] = []
69135
@@ -72,11 +138,6 @@ def __init__(
72138 #: Type of layer taken as input
73139 input_layer_types : Tuple [napari .layers .Layer , ...] = (napari .layers .Layer ,)
74140
75- @property
76- def figure (self ) -> Figure :
77- """Matplotlib figure."""
78- return self .canvas .figure
79-
80141 @property
81142 def n_selected_layers (self ) -> int :
82143 """
@@ -102,14 +163,16 @@ def _setup_callbacks(self) -> None:
102163 # z-step changed in viewer
103164 self .viewer .dims .events .current_step .connect (self ._draw )
104165 # Layer selection changed in viewer
105- self .viewer .layers .selection .events .changed .connect (self .update_layers )
166+ self .viewer .layers .selection .events .changed .connect (
167+ self ._update_layers
168+ )
106169
107- def update_layers (self , event : napari .utils .events .Event ) -> None :
170+ def _update_layers (self , event : napari .utils .events .Event ) -> None :
108171 """
109172 Update the ``layers`` attribute with currently selected layers and re-draw.
110173 """
111174 self .layers = list (self .viewer .layers .selection )
112- self ._on_update_layers ()
175+ self .on_update_layers ()
113176 self ._draw ()
114177
115178 def _draw (self ) -> None :
@@ -138,58 +201,13 @@ def draw(self) -> None:
138201 This is a no-op, and is intended for derived classes to override.
139202 """
140203
141- def add_single_axes (self ) -> None :
142- """
143- Add a single Axes to the figure.
144-
145- The Axes is saved on the ``.axes`` attribute for later access.
204+ def on_update_layers (self ) -> None :
146205 """
147- self .axes = self .figure .subplots ()
148- self .apply_napari_colorscheme (self .axes )
149-
150- @staticmethod
151- def apply_napari_colorscheme (ax : Axes ) -> None :
152- """Apply napari-compatible colorscheme to an Axes."""
153- # changing color of axes background to transparent
154- ax .set_facecolor ("none" )
155-
156- # changing colors of all axes
157- for spine in ax .spines :
158- ax .spines [spine ].set_color ("white" )
159-
160- ax .xaxis .label .set_color ("white" )
161- ax .yaxis .label .set_color ("white" )
162-
163- # changing colors of axes labels
164- ax .tick_params (axis = "x" , colors = "white" )
165- ax .tick_params (axis = "y" , colors = "white" )
166-
167- def _on_update_layers (self ) -> None :
168- """
169- Function is called when self.layers is updated via
170- ``self.update_layers()``.
206+ Called when the selected layers are updated.
171207
172208 This is a no-op, and is intended for derived classes to override.
173209 """
174210
175- def _replace_toolbar_icons (self ) -> None :
176- # Modify toolbar icons and some tooltips
177- for action in self .toolbar .actions ():
178- text = action .text ()
179- if text == "Pan" :
180- action .setToolTip (
181- "Pan/Zoom: Left button pans; Right button zooms; "
182- "Click once to activate; Click again to deactivate"
183- )
184- if text == "Zoom" :
185- action .setToolTip (
186- "Zoom to rectangle; Click once to activate; "
187- "Click again to deactivate"
188- )
189- if len (text ) > 0 : # i.e. not a separator item
190- icon_path = os .path .join (ICON_ROOT , text + ".png" )
191- action .setIcon (QIcon (icon_path ))
192-
193211
194212class NapariNavigationToolbar (NavigationToolbar2QT ):
195213 """Custom Toolbar style for Napari."""
0 commit comments