Skip to content
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

Deselect clusters #291

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
54 changes: 45 additions & 9 deletions napari_clusters_plotter/_Qt_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
from matplotlib.path import Path
from matplotlib.widgets import LassoSelector, RectangleSelector, SpanSelector
from napari.layers import Image, Layer
from qtpy.QtCore import QRect
from qtpy.QtGui import QIcon
from qtpy.QtCore import QRect, Qt
from qtpy.QtGui import QGuiApplication, QIcon
from qtpy.QtWidgets import (
QAbstractItemView,
QHBoxLayout,
Expand Down Expand Up @@ -390,24 +390,54 @@


class SelectFrom2DHistogram:
def __init__(self, parent, ax, full_data):
def __init__(self, parent, ax, full_data, histogram):
self.parent = parent
self.ax = ax
self.canvas = ax.figure.canvas
self.xys = full_data
self.cluster_id_histo_overlay = None
self.histogram = histogram

Check warning on line 399 in napari_clusters_plotter/_Qt_code.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_Qt_code.py#L398-L399

Added lines #L398 - L399 were not covered by tests

self.lasso = LassoSelector(ax, onselect=self.onselect)
self.ind = []
self.ind_mask = []

def vert_to_coord(self, vert):
"""
Converts verticis to histogram coordinates in pixels
"""

# I tried to solve it with self.ax.transData.transform... but it did not work...
xrange = self.histogram[1][-1] - self.histogram[1][0]
yrange = self.histogram[2][-1] - self.histogram[2][0]
v = (

Check warning on line 413 in napari_clusters_plotter/_Qt_code.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_Qt_code.py#L411-L413

Added lines #L411 - L413 were not covered by tests
(vert[0] - self.histogram[1][0]) / (xrange) * self.histogram[0].shape[0],
(vert[1] - self.histogram[2][0]) / (yrange) * self.histogram[0].shape[1],
)

coord = tuple([int(c) for c in v])
return coord

Check warning on line 419 in napari_clusters_plotter/_Qt_code.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_Qt_code.py#L418-L419

Added lines #L418 - L419 were not covered by tests

def onselect(self, verts):
path = Path(verts)
if self.parent.manual_clustering_method is None:
return

Check warning on line 423 in napari_clusters_plotter/_Qt_code.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_Qt_code.py#L422-L423

Added lines #L422 - L423 were not covered by tests

self.ind_mask = path.contains_points(self.xys)
self.ind = np.nonzero(self.ind_mask)[0]
modifiers = QGuiApplication.keyboardModifiers()

Check warning on line 425 in napari_clusters_plotter/_Qt_code.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_Qt_code.py#L425

Added line #L425 was not covered by tests

if self.parent.manual_clustering_method is not None:
self.parent.manual_clustering_method(self.ind_mask)
if (

Check warning on line 427 in napari_clusters_plotter/_Qt_code.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_Qt_code.py#L427

Added line #L427 was not covered by tests
modifiers == Qt.ControlModifier and len(verts) == 2
): # has len of 2 when single click was done
coord_click = self.vert_to_coord(verts[0])
cluster_id_to_delete = self.cluster_id_histo_overlay[coord_click[::-1]][0]
if cluster_id_to_delete > 0:
self.parent.manual_clustering_method(

Check warning on line 433 in napari_clusters_plotter/_Qt_code.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_Qt_code.py#L430-L433

Added lines #L430 - L433 were not covered by tests
np.zeros(shape=self.xys.shape), delete_cluster=cluster_id_to_delete
)
return

Check warning on line 436 in napari_clusters_plotter/_Qt_code.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_Qt_code.py#L436

Added line #L436 was not covered by tests

path = Path(verts)
self.ind_mask = path.contains_points(self.xys)
self.parent.manual_clustering_method(self.ind_mask)

Check warning on line 440 in napari_clusters_plotter/_Qt_code.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_Qt_code.py#L438-L440

Added lines #L438 - L440 were not covered by tests

def disconnect(self):
self.lasso.disconnect_events()
Expand Down Expand Up @@ -521,6 +551,7 @@
def __init__(self, parent=None, width=7, height=4, manual_clustering_method=None):
self.fig = Figure(figsize=(width, height), constrained_layout=True)
self.manual_clustering_method = manual_clustering_method
self.parent = parent

self.axes = self.fig.add_subplot(111)
self.histogram = None
Expand Down Expand Up @@ -552,6 +583,9 @@

self.reset()

def set_selector_cluster_id_overlay(self, overlay: np.array):
self.selector.cluster_id_histo_overlay = overlay

Check warning on line 587 in napari_clusters_plotter/_Qt_code.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_Qt_code.py#L587

Added line #L587 was not covered by tests

def reset_zoom(self):
if self.xylim:
self.axes.set_xlim(self.xylim[0])
Expand Down Expand Up @@ -619,7 +653,9 @@
self.axes.set_ylim(yedges[0], yedges[-1])
self.histogram = (h, xedges, yedges)
self.selector.disconnect()
self.selector = SelectFrom2DHistogram(self, self.axes, self.full_data)
self.selector = SelectFrom2DHistogram(

Check warning on line 656 in napari_clusters_plotter/_Qt_code.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_Qt_code.py#L656

Added line #L656 was not covered by tests
self, self.axes, self.full_data, self.histogram
)
self.axes.figure.canvas.draw_idle()

def make_1d_histogram(
Expand Down
17 changes: 14 additions & 3 deletions napari_clusters_plotter/_plotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,9 @@

self.analysed_layer = None
self.visualized_layer = None
self.cluster_id_histo_overlay = None

def manual_clustering_method(inside):
def manual_clustering_method(inside, **kwargs):
inside = np.array(inside) # leads to errors sometimes otherwise

if self.analysed_layer is None or len(inside) == 0:
Expand All @@ -101,7 +102,14 @@
features = get_layer_tabular_data(self.analysed_layer)

modifiers = QGuiApplication.keyboardModifiers()
if modifiers == Qt.ShiftModifier and clustering_ID in features.keys():
if "delete_cluster" in kwargs:
features[clustering_ID].mask(

Check warning on line 106 in napari_clusters_plotter/_plotter.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_plotter.py#L105-L106

Added lines #L105 - L106 were not covered by tests
features[clustering_ID] == kwargs["delete_cluster"],
other=-1,
inplace=True,
)

elif modifiers == Qt.ShiftModifier and clustering_ID in features.keys():

Check warning on line 112 in napari_clusters_plotter/_plotter.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_plotter.py#L112

Added line #L112 was not covered by tests
features[clustering_ID].mask(
inside, other=features[clustering_ID].max() + 1, inplace=True
)
Expand Down Expand Up @@ -677,7 +685,7 @@
log_scale=self.log_scale.isChecked(),
)

rgb_img = make_cluster_overlay_img(
rgb_img, self.cluster_id_histo_overlay = make_cluster_overlay_img(

Check warning on line 688 in napari_clusters_plotter/_plotter.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_plotter.py#L688

Added line #L688 was not covered by tests
cluster_id=plot_cluster_name,
features=features,
feature_x=self.plot_x_axis_name,
Expand All @@ -686,6 +694,9 @@
histogram_data=self.graphics_widget.histogram,
hide_first_cluster=self.plot_hide_non_selected.isChecked(),
)
self.graphics_widget.set_selector_cluster_id_overlay(

Check warning on line 697 in napari_clusters_plotter/_plotter.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_plotter.py#L697

Added line #L697 was not covered by tests
self.cluster_id_histo_overlay
)
xedges = self.graphics_widget.histogram[1]
yedges = self.graphics_widget.histogram[2]

Expand Down
6 changes: 5 additions & 1 deletion napari_clusters_plotter/_plotter_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,7 @@
]

cluster_overlay_rgba = np.zeros((*h.shape, 4), dtype=float)
cluster_overlay_cluster_id = np.zeros((*h.shape, 1), dtype=int)

Check warning on line 552 in napari_clusters_plotter/_plotter_utilities.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_plotter_utilities.py#L552

Added line #L552 was not covered by tests
output_max = np.zeros(h.shape, dtype=float)

for cluster, entries in relevant_entries.groupby(cluster_id):
Expand All @@ -565,5 +566,8 @@
]
rgba.append(0.9)
cluster_overlay_rgba[mask] = rgba
cluster_overlay_cluster_id[mask] = cluster

Check warning on line 569 in napari_clusters_plotter/_plotter_utilities.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_plotter_utilities.py#L569

Added line #L569 was not covered by tests

return cluster_overlay_rgba.swapaxes(0, 1)
return cluster_overlay_rgba.swapaxes(0, 1), cluster_overlay_cluster_id.swapaxes(

Check warning on line 571 in napari_clusters_plotter/_plotter_utilities.py

View check run for this annotation

Codecov / codecov/patch

napari_clusters_plotter/_plotter_utilities.py#L571

Added line #L571 was not covered by tests
0, 1
)
Loading