forked from matplotlib/napari-matplotlib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathslice.py
118 lines (94 loc) · 3.2 KB
/
slice.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
from typing import Any, Dict, Optional, Tuple
import napari
import numpy as np
import numpy.typing as npt
from qtpy.QtWidgets import QComboBox, QHBoxLayout, QLabel, QSpinBox, QWidget
from .base import SingleAxesWidget
from .util import Interval
__all__ = ["SliceWidget"]
_dims_sel = ["x", "y"]
_dims = ["x", "y", "z"]
class SliceWidget(SingleAxesWidget):
"""
Plot a 1D slice along a given dimension.
"""
n_layers_input = Interval(1, 1)
input_layer_types = (napari.layers.Image,)
def __init__(
self,
napari_viewer: napari.viewer.Viewer,
parent: Optional[QWidget] = None,
):
# Setup figure/axes
super().__init__(napari_viewer, parent=parent)
button_layout = QHBoxLayout()
self.layout().addLayout(button_layout)
self.dim_selector = QComboBox()
button_layout.addWidget(QLabel("Slice axis:"))
button_layout.addWidget(self.dim_selector)
self.dim_selector.addItems(_dims)
self.slice_selectors = {}
for d in _dims_sel:
self.slice_selectors[d] = QSpinBox()
button_layout.addWidget(QLabel(f"{d}:"))
button_layout.addWidget(self.slice_selectors[d])
# Setup callbacks
# Re-draw when any of the combon/spin boxes are updated
self.dim_selector.currentTextChanged.connect(self._draw)
for d in _dims_sel:
self.slice_selectors[d].textChanged.connect(self._draw)
self._update_layers(None)
@property
def _layer(self) -> napari.layers.Layer:
"""
Layer being plotted.
"""
return self.layers[0]
@property
def current_dim(self) -> str:
"""
Currently selected slice dimension.
"""
return self.dim_selector.currentText()
@property
def current_dim_index(self) -> int:
"""
Currently selected slice dimension index.
"""
# Note the reversed list because in napari the z-axis is the first
# numpy axis
return _dims[::-1].index(self.current_dim)
@property
def _selector_values(self) -> Dict[str, int]:
"""
Values of the slice selectors.
"""
return {d: self.slice_selectors[d].value() for d in _dims_sel}
def _get_xy(self) -> Tuple[npt.NDArray[Any], npt.NDArray[Any]]:
"""
Get data for plotting.
"""
x = np.arange(self._layer.data.shape[self.current_dim_index])
vals = self._selector_values
vals.update({"z": self.current_z})
slices = []
for d in _dims:
if d == self.current_dim:
# Select all data along this axis
slices.append(slice(None))
else:
# Select specific index
val = vals[d]
slices.append(slice(val, val + 1))
# Reverse since z is the first axis in napari
slices = slices[::-1]
y = self._layer.data[tuple(slices)].ravel()
return x, y
def draw(self) -> None:
"""
Clear axes and draw a 1D plot.
"""
x, y = self._get_xy()
self.axes.plot(x, y)
self.axes.set_xlabel(self.current_dim)
self.axes.set_title(self._layer.name)