Skip to content

FeaturesLineWidget #200

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
remove line widget
  • Loading branch information
zoccoler committed Jul 29, 2023
commit 7fff19509f6832cdc1bf6170658115c2a1dae28c
16 changes: 0 additions & 16 deletions examples/line_profile.py

This file was deleted.

Binary file removed examples/line_widget.gif
Binary file not shown.
88 changes: 8 additions & 80 deletions src/napari_matplotlib/line.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,78 +53,6 @@ def _get_data(self) -> Tuple[npt.NDArray[Any], npt.NDArray[Any], str, str]:
raise NotImplementedError


class LineWidget(LineBaseWidget):
"""
Plot pixel values of an Image layer underneath a line from a Shapes layer.
"""

n_layers_input = Interval(2, 2)
input_layer_types = (napari.layers.Image,
napari.layers.Shapes,)

def _get_data(self) -> Tuple[npt.NDArray[Any], npt.NDArray[Any], str, str]:
"""
Get the plot data.

Returns
-------
x, y : np.ndarray
x and y values of plot data.
x_axis_name : str
The title to display on the x axis
y_axis_name: str
The title to display on the y axis
"""
line_data = self._get_line_data()
if line_data is None:
return [], [], "", ""
image_layers = [layer for layer in self.layers if isinstance(layer, napari.layers.Image)]
if len(image_layers) == 0:
return [], [], "", ""
line_pixel_coords = self._get_line_pixel_coordinates(
line_data[0], line_data[1], weight=1, shape=image_layers[0].data.shape)

x = self._get_pixel_distances(line_pixel_coords, line_data[0])
y = image_layers[0].data[self.current_z][line_pixel_coords[0], line_pixel_coords[1]]
x_axis_name = 'pixel distance'
y_axis_name = image_layers[0].name

return x, y, x_axis_name, y_axis_name

def _get_line_data(self):
"""
Get the line data from the Shapes layer.
"""
for layer in self.layers:
# There must be a Shapes layer
if isinstance(layer, napari.layers.Shapes):
# There must be a line
if 'line' in layer.shape_type:
line_data = layer.data[layer.shape_type.index('line')]
return line_data
return None

def _get_line_pixel_coordinates(self, start, end, weight=1, shape=None):
"""
Get the pixel coordinates of a line from start to end using a bezier curve.
"""
import numpy as np
from skimage.draw import bezier_curve
middle = (start + end) / 2
start = np.round(start).astype(int)
middle = np.round(middle).astype(int)
end = np.round(end).astype(int)
rr, cc = bezier_curve(start[0], start[1], middle[0], middle[1], end[0], end[1], weight=weight, shape=shape)
return np.array([rr, cc])

def _get_pixel_distances(self, line_coordinates, start):
"""
Get the pixel distances from the start of the line.
"""
distances = np.linalg.norm(line_coordinates - start[:, np.newaxis], axis=0)
return distances


class FeaturesLineWidget(LineBaseWidget):
"""
Widget to do line plots of two features from a layer, grouped by label.
Expand All @@ -147,10 +75,10 @@ def __init__(

self._selectors: Dict[str, QComboBox] = {}
# Add split-by selector
self._selectors["label"] = QComboBox()
self._selectors["label"].currentTextChanged.connect(self._draw)
self.layout().addWidget(QLabel(f"label:"))
self.layout().addWidget(self._selectors["label"])
self._selectors["object_id"] = QComboBox()
self._selectors["object_id"].currentTextChanged.connect(self._draw)
self.layout().addWidget(QLabel(f"object-id:"))
self.layout().addWidget(self._selectors["object_id"])

for dim in ["x", "y"]:
self._selectors[dim] = QComboBox()
Expand Down Expand Up @@ -197,14 +125,14 @@ def label_axis_key(self) -> Union[str, None]:
"""
Key for the label factor.
"""
if self._selectors["label"].count() == 0:
if self._selectors["object_id"].count() == 0:
return None
else:
return self._selectors["label"].currentText()
return self._selectors["object_id"].currentText()

@label_axis_key.setter
def label_axis_key(self, key: str) -> None:
self._selectors["label"].setCurrentText(key)
self._selectors["object_id"].setCurrentText(key)
self._draw()

def _get_valid_axis_keys(self) -> List[str]:
Expand Down Expand Up @@ -307,7 +235,7 @@ def on_update_layers(self) -> None:
Called when the layer selection changes by ``self.update_layers()``.
"""
# Clear combobox
for dim in ["label", "x", "y"]:
for dim in ["object_id", "x", "y"]:
while self._selectors[dim].count() > 0:
self._selectors[dim].removeItem(0)
# Add keys for newly selected layer
Expand Down