4
4
FigureCanvas ,
5
5
NavigationToolbar2QT ,
6
6
)
7
- from matplotlib .figure import Figure
8
7
from qtpy .QtWidgets import QVBoxLayout , QWidget
9
8
10
9
mpl .rc ("axes" , edgecolor = "white" )
15
14
16
15
mpl .rc ("xtick" , color = "white" )
17
16
mpl .rc ("ytick" , color = "white" )
17
+
18
18
__all__ = ["NapariMPLWidget" ]
19
19
20
20
@@ -23,8 +23,12 @@ class NapariMPLWidget(QWidget):
23
23
Base widget that can be embedded as a napari widget and contains a
24
24
Matplotlib canvas.
25
25
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.
28
32
29
33
Attributes
30
34
----------
@@ -34,13 +38,14 @@ class NapariMPLWidget(QWidget):
34
38
Matplotlib figure.
35
39
canvas : matplotlib.backends.backend_qt5agg.FigureCanvas
36
40
Matplotlib canvas.
41
+ layers : `list`
42
+ List of currently selected napari layers.
37
43
"""
38
44
39
45
def __init__ (self , napari_viewer : napari .viewer .Viewer ):
40
46
super ().__init__ ()
41
47
42
48
self .viewer = napari_viewer
43
- self .figure = Figure (figsize = (5 , 3 ), tight_layout = True )
44
49
self .canvas = FigureCanvas ()
45
50
self .canvas .figure .patch .set_facecolor ("#262930" )
46
51
self .toolbar = NavigationToolbar2QT (self .canvas , self )
@@ -49,9 +54,61 @@ def __init__(self, napari_viewer: napari.viewer.Viewer):
49
54
self .layout ().addWidget (self .toolbar )
50
55
self .layout ().addWidget (self .canvas )
51
56
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
+
52
66
@property
53
67
def current_z (self ) -> int :
54
68
"""
55
69
Current z-step of the viewer.
56
70
"""
57
71
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