44 FigureCanvas ,
55 NavigationToolbar2QT ,
66)
7- from matplotlib .figure import Figure
87from qtpy .QtWidgets import QVBoxLayout , QWidget
98
109mpl .rc ("axes" , edgecolor = "white" )
1514
1615mpl .rc ("xtick" , color = "white" )
1716mpl .rc ("ytick" , color = "white" )
17+
1818__all__ = ["NapariMPLWidget" ]
1919
2020
@@ -23,8 +23,12 @@ class NapariMPLWidget(QWidget):
2323 Base widget that can be embedded as a napari widget and contains a
2424 Matplotlib canvas.
2525
26- This creates a single Figure, and sub-classes should implement logic for
27- drawing on that Figure.
26+ This creates a single FigureCanvas, which contains a single Figure.
27+
28+ This class also handles callbacks to automatically update figures when
29+ the layer selection or z-step is changed in the napari viewer. To take
30+ advantage of this sub-classes should implement the ``clear()`` and
31+ ``draw()`` methods.
2832
2933 Attributes
3034 ----------
@@ -34,13 +38,14 @@ class NapariMPLWidget(QWidget):
3438 Matplotlib figure.
3539 canvas : matplotlib.backends.backend_qt5agg.FigureCanvas
3640 Matplotlib canvas.
41+ layers : `list`
42+ List of currently selected napari layers.
3743 """
3844
3945 def __init__ (self , napari_viewer : napari .viewer .Viewer ):
4046 super ().__init__ ()
4147
4248 self .viewer = napari_viewer
43- self .figure = Figure (figsize = (5 , 3 ), tight_layout = True )
4449 self .canvas = FigureCanvas ()
4550 self .canvas .figure .patch .set_facecolor ("#262930" )
4651 self .toolbar = NavigationToolbar2QT (self .canvas , self )
@@ -49,9 +54,61 @@ def __init__(self, napari_viewer: napari.viewer.Viewer):
4954 self .layout ().addWidget (self .toolbar )
5055 self .layout ().addWidget (self .canvas )
5156
57+ self .setup_callbacks ()
58+
59+ @property
60+ def n_selected_layers (self ) -> int :
61+ """
62+ Number of currently selected layers.
63+ """
64+ return len (self .layers )
65+
5266 @property
5367 def current_z (self ) -> int :
5468 """
5569 Current z-step of the viewer.
5670 """
5771 return self .viewer .dims .current_step [0 ]
72+
73+ def setup_callbacks (self ) -> None :
74+ """
75+ Setup callbacks for:
76+ - Layer selection changing
77+ - z-step changing
78+ """
79+ # z-step changed in viewer
80+ self .viewer .dims .events .current_step .connect (self ._draw )
81+ # Layer selection changed in viewer
82+ self .viewer .layers .selection .events .active .connect (self .update_layers )
83+
84+ def update_layers (self , event : napari .utils .events .Event ) -> None :
85+ """
86+ Update the currently selected layers and re-draw.
87+ """
88+ self .layers = list (self .viewer .layers .selection )
89+ self ._draw ()
90+
91+ def _draw (self ) -> None :
92+ """
93+ Clear current figure, check selected layers are correct, and draw new
94+ figure if so.
95+ """
96+ self .clear ()
97+ if self .n_selected_layers != self .n_layers_input :
98+ return
99+ self .draw ()
100+ self .canvas .draw ()
101+
102+ def clear (self ) -> None :
103+ """
104+ Clear any previously drawn figures.
105+
106+ This is a no-op, and is intended for derived classes to override.
107+ """
108+
109+ def draw (self ) -> None :
110+ """
111+ Re-draw any figures.
112+
113+ This is a no-op, and is intended for derived classes to override.
114+ """
0 commit comments