Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
27 changes: 27 additions & 0 deletions src/napari_clusters_plotter/_algorithm_widget.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import warnings

import pandas as pd
from magicgui import magicgui
from napari.layers import (
Expand Down Expand Up @@ -50,6 +52,13 @@
].astype("category")
return features.reset_index(drop=True)

def _clean_up(self):
"""Determines what happens in case of no layer selected"""

raise NotImplementedError(

Check warning on line 58 in src/napari_clusters_plotter/_algorithm_widget.py

View check run for this annotation

Codecov / codecov/patch

src/napari_clusters_plotter/_algorithm_widget.py#L58

Added line #L58 was not covered by tests
"This function should be implemented in the subclass."
)

@property
def common_columns(self):
if len(self.layers) == 0:
Expand Down Expand Up @@ -137,6 +146,13 @@
return features

def _wait_for_finish(self, worker):
# escape empty input data
if self.selected_algorithm_widget.data.value.empty:
warnings.warn(

Check warning on line 151 in src/napari_clusters_plotter/_algorithm_widget.py

View check run for this annotation

Codecov / codecov/patch

src/napari_clusters_plotter/_algorithm_widget.py#L151

Added line #L151 was not covered by tests
"No features selected. Please select features before running the algorithm.",
stacklevel=1,
)
return

Check warning on line 155 in src/napari_clusters_plotter/_algorithm_widget.py

View check run for this annotation

Codecov / codecov/patch

src/napari_clusters_plotter/_algorithm_widget.py#L155

Added line #L155 was not covered by tests
self.worker = worker
self.worker.start()
self.worker.returned.connect(self._process_result)
Expand Down Expand Up @@ -164,6 +180,7 @@

# don't do anything if no layer is selected
if self.n_selected_layers == 0:
self._clean_up()
return

# check if the selected layers are of the correct type
Expand All @@ -189,6 +206,16 @@
self.feature_selection_widget.addItems(sorted(features_to_add.columns))
self._update_features()

def _clean_up(self):
"""
Clean up the widget when it is closed.
"""

# block signals for feature selection
self.feature_selection_widget.blockSignals(True)
self.feature_selection_widget.clear()
self.feature_selection_widget.blockSignals(False)

@property
def selected_algorithm(self):
return self.algorithm_selection.currentText()
25 changes: 25 additions & 0 deletions src/napari_clusters_plotter/_new_plotter_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@
# if the hue axis is not set to MANUAL_CLUSTER_ID, set it to that
# otherwise replot the data

if self.n_selected_layers == 0:
return

Check warning on line 153 in src/napari_clusters_plotter/_new_plotter_widget.py

View check run for this annotation

Codecov / codecov/patch

src/napari_clusters_plotter/_new_plotter_widget.py#L153

Added line #L153 was not covered by tests

features = self._get_features()
for layer in self.viewer.layers.selection:
layer_indices = features[features["layer"] == layer.name].index
Expand Down Expand Up @@ -335,6 +338,7 @@
"""
# don't do anything if no layer is selected
if self.n_selected_layers == 0:
self._clean_up()
return

# check if the selected layers are of the correct type
Expand Down Expand Up @@ -362,6 +366,23 @@
for layer in self.layers:
layer.events.features.connect(self._update_feature_selection)

def _clean_up(self):
"""In case of empty layer selection"""

# disconnect the events from the layers
for layer in self.viewer.layers.selection:
layer.events.features.disconnect(self._update_feature_selection)

Check warning on line 374 in src/napari_clusters_plotter/_new_plotter_widget.py

View check run for this annotation

Codecov / codecov/patch

src/napari_clusters_plotter/_new_plotter_widget.py#L374

Added line #L374 was not covered by tests

# reset the selected layers
self.layers = []

# reset the selectors
for dim in ["x", "y", "hue"]:
selector = self._selectors[dim]
selector.blockSignals(True)
selector.clear()
selector.blockSignals(False)

def _update_feature_selection(
self, event: napari.utils.events.Event
) -> None:
Expand Down Expand Up @@ -450,6 +471,10 @@
"""
Reset the selection in the current plotting widget.
"""

if self.n_selected_layers == 0:
return

self.plotting_widget.active_artist.color_indices = np.zeros(
len(self._get_features())
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ def test_initialization(make_napari_viewer, widget_config):
# check that all features are in reduce_wdiget.feature_selection_widget
assert len(feature_selection_items) == len(layer.features.columns)

# clear layers to make sure cleanup works
viewer.layers.clear()

assert widget.feature_selection_widget.count() == 0


def test_layer_update(make_napari_viewer, widget_config):
viewer = make_napari_viewer()
Expand Down
39 changes: 39 additions & 0 deletions src/napari_clusters_plotter/_tests/test_plotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,45 @@ def test_categorical_handling(make_napari_viewer, create_sample_layers):
assert categorical_columns[1] == "layer"


def test_empty_layer_clean_up(make_napari_viewer, n_samples: int = 100):
"""
This test checks what happenns when you add some layers,
do a manual clustering , then delete the layers and add some others
"""
from napari_clusters_plotter import PlotterWidget

viewer = make_napari_viewer()

points1, points2 = create_multi_point_layer(n_samples=n_samples)
vectors1, _ = create_multi_vectors_layer(n_samples=n_samples)

# add points to viewer
viewer.add_layer(points1)
viewer.add_layer(points2)

widget = PlotterWidget(viewer)
viewer.window.add_dock_widget(widget, area="right")
viewer.layers.selection.active = points1

# do a random drawing
assert "MANUAL_CLUSTER_ID" in points1.features.columns
random_cluster_indeces = np.random.randint(0, 2, len(points1.data))
widget._on_finish_draw(random_cluster_indeces)

# delete the layers
viewer.layers.clear()

# check that all widget._selectros ('x', 'y', 'hue') are empty
assert widget._selectors["x"].currentText() == ""
assert widget._selectors["y"].currentText() == ""
assert widget._selectors["hue"].currentText() == ""

widget._reset()

# add vectors to viewer
viewer.add_layer(vectors1)


@pytest.mark.parametrize(
"create_sample_layers",
[
Expand Down