1- from typing import Any , Dict , List , Optional , Tuple
1+ from typing import Any , List , Optional , Tuple
22
33import matplotlib .ticker as mticker
44import napari
55import numpy as np
66import numpy .typing as npt
7- from qtpy .QtWidgets import QComboBox , QHBoxLayout , QLabel , QSpinBox , QWidget
7+ from qtpy .QtCore import Qt
8+ from qtpy .QtWidgets import (
9+ QComboBox ,
10+ QLabel ,
11+ QSlider ,
12+ QVBoxLayout ,
13+ QWidget ,
14+ )
815
916from .base import SingleAxesWidget
1017from .util import Interval
1118
1219__all__ = ["SliceWidget" ]
1320
14- _dims_sel = ["x" , "y" ]
15-
1621
1722class SliceWidget (SingleAxesWidget ):
1823 """
@@ -30,28 +35,46 @@ def __init__(
3035 # Setup figure/axes
3136 super ().__init__ (napari_viewer , parent = parent )
3237
33- button_layout = QHBoxLayout ()
34- self .layout ().addLayout (button_layout )
35-
3638 self .dim_selector = QComboBox ()
39+ self .dim_selector .addItems (["x" , "y" ])
40+
41+ self .slice_selector = QSlider (orientation = Qt .Orientation .Horizontal )
42+
43+ # Create widget layout
44+ button_layout = QVBoxLayout ()
3745 button_layout .addWidget (QLabel ("Slice axis:" ))
3846 button_layout .addWidget (self .dim_selector )
39- self .dim_selector .addItems (["x" , "y" , "z" ])
40-
41- self .slice_selectors = {}
42- for d in _dims_sel :
43- self .slice_selectors [d ] = QSpinBox ()
44- button_layout .addWidget (QLabel (f"{ d } :" ))
45- button_layout .addWidget (self .slice_selectors [d ])
47+ button_layout .addWidget (self .slice_selector )
48+ self .layout ().addLayout (button_layout )
4649
4750 # Setup callbacks
48- # Re-draw when any of the combon/spin boxes are updated
51+ # Re-draw when any of the combo/slider is updated
4952 self .dim_selector .currentTextChanged .connect (self ._draw )
50- for d in _dims_sel :
51- self .slice_selectors [d ].textChanged .connect (self ._draw )
53+ self .slice_selector .valueChanged .connect (self ._draw )
5254
5355 self ._update_layers (None )
5456
57+ def on_update_layers (self ) -> None :
58+ """
59+ Called when layer selection is updated.
60+ """
61+ if not len (self .layers ):
62+ return
63+ if self .current_dim_name == "x" :
64+ max = self ._layer .data .shape [- 2 ]
65+ elif self .current_dim_name == "y" :
66+ max = self ._layer .data .shape [- 1 ]
67+ else :
68+ raise RuntimeError ("dim name must be x or y" )
69+ self .slice_selector .setRange (0 , max - 1 )
70+
71+ @property
72+ def _slice_width (self ) -> int :
73+ """
74+ Width of the slice being plotted.
75+ """
76+ return self ._layer .data .shape [self .current_dim_index ]
77+
5578 @property
5679 def _layer (self ) -> napari .layers .Layer :
5780 """
@@ -73,7 +96,7 @@ def current_dim_index(self) -> int:
7396 """
7497 # Note the reversed list because in napari the z-axis is the first
7598 # numpy axis
76- return self ._dim_names [:: - 1 ] .index (self .current_dim_name )
99+ return self ._dim_names .index (self .current_dim_name )
77100
78101 @property
79102 def _dim_names (self ) -> List [str ]:
@@ -82,45 +105,31 @@ def _dim_names(self) -> List[str]:
82105 dimensionality of the currently selected data.
83106 """
84107 if self ._layer .data .ndim == 2 :
85- return ["x " , "y " ]
108+ return ["y " , "x " ]
86109 elif self ._layer .data .ndim == 3 :
87- return ["x " , "y" , "z " ]
110+ return ["z " , "y" , "x " ]
88111 else :
89112 raise RuntimeError ("Don't know how to handle ndim != 2 or 3" )
90113
91- @property
92- def _selector_values (self ) -> Dict [str , int ]:
93- """
94- Values of the slice selectors.
95-
96- Mapping from dimension name to value.
97- """
98- return {d : self .slice_selectors [d ].value () for d in _dims_sel }
99-
100114 def _get_xy (self ) -> Tuple [npt .NDArray [Any ], npt .NDArray [Any ]]:
101115 """
102116 Get data for plotting.
103117 """
104- dim_index = self .current_dim_index
105- if self ._layer .data .ndim == 2 :
106- dim_index -= 1
107- x = np .arange (self ._layer .data .shape [dim_index ])
108-
109- vals = self ._selector_values
110- vals .update ({"z" : self .current_z })
118+ val = self .slice_selector .value ()
111119
112120 slices = []
113121 for dim_name in self ._dim_names :
114122 if dim_name == self .current_dim_name :
115123 # Select all data along this axis
116124 slices .append (slice (None ))
125+ elif dim_name == "z" :
126+ # Only select the currently viewed z-index
127+ slices .append (slice (self .current_z , self .current_z + 1 ))
117128 else :
118129 # Select specific index
119- val = vals [dim_name ]
120130 slices .append (slice (val , val + 1 ))
121131
122- # Reverse since z is the first axis in napari
123- slices = slices [::- 1 ]
132+ x = np .arange (self ._slice_width )
124133 y = self ._layer .data [tuple (slices )].ravel ()
125134
126135 return x , y
0 commit comments