forked from matplotlib/napari-matplotlib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathslice.py
129 lines (103 loc) · 3.5 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
119
120
121
122
123
124
125
126
127
128
129
from typing import Dict, Tuple
import napari
import numpy as np
from qtpy.QtWidgets import QComboBox, QHBoxLayout, QLabel, QSpinBox
from .base import NapariMPLWidget
from .util import Interval
__all__ = ["SliceWidget"]
_dims_sel = ["x", "y"]
_dims = ["x", "y", "z"]
class SliceWidget(NapariMPLWidget):
"""
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):
# Setup figure/axes
super().__init__(napari_viewer)
self.axes = self.canvas.figure.subplots()
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):
"""
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 update_slice_selectors(self) -> None:
"""
Update range and enabled status of the slice selectors, and the value
of the z slice selector.
"""
# Update min/max
for i, dim in enumerate(_dims_sel):
self.slice_selectors[dim].setRange(0, self.layer.data.shape[i])
def get_xy(self) -> Tuple[np.ndarray, np.ndarray]:
"""
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 clear(self) -> None:
"""
Clear the axes.
"""
self.axes.cla()
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)