Skip to content

Commit

Permalink
Merge branch 'main' into extend_readme_zero_labels
Browse files Browse the repository at this point in the history
  • Loading branch information
Cryaaa committed Dec 11, 2023
2 parents cca2a35 + 9398680 commit 779cac0
Show file tree
Hide file tree
Showing 13 changed files with 673 additions and 204 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![PyPI](https://img.shields.io/pypi/v/napari-clusters-plotter.svg?color=green)](https://pypi.org/project/napari-clusters-plotter)
[![Python Version](https://img.shields.io/pypi/pyversions/napari-clusters-plotter.svg?color=green)](https://python.org)
[![Anaconda-Server Badge](https://anaconda.org/conda-forge/napari-clusters-plotter/badges/version.svg)](https://anaconda.org/conda-forge/napari-clusters-plotter)
[![tests](https://github.com/BiAPoL/napari-clusters-plotter/workflows/tests/badge.svg)](https://github.com/BiAPoL/napari-clusters-plotter/actions)
[![tests](https://github.com/BiAPoL/napari-clusters-plotter/actions/workflows/test_and_deploy.yml/badge.svg)](https://github.com/BiAPoL/napari-clusters-plotter/actions/workflows/test_and_deploy.yml)
[![codecov](https://codecov.io/gh/BiAPoL/napari-clusters-plotter/branch/main/graph/badge.svg?token=R6W2KO1NJ8)](https://codecov.io/gh/BiAPoL/napari-clusters-plotter)
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)
[![Anaconda-Server Badge](https://anaconda.org/conda-forge/napari-clusters-plotter/badges/downloads.svg)](https://anaconda.org/conda-forge/napari-clusters-plotter)
Expand Down
36 changes: 24 additions & 12 deletions napari_clusters_plotter/_Qt_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from matplotlib.figure import Figure
from matplotlib.path import Path
from matplotlib.widgets import LassoSelector, RectangleSelector, SpanSelector
from napari.layers import Image, Labels
from napari.layers import Image, Layer
from qtpy.QtCore import QRect
from qtpy.QtGui import QIcon
from qtpy.QtWidgets import (
Expand Down Expand Up @@ -52,22 +52,22 @@ def measurements_container_and_list():
return properties_container, properties_list


def labels_container_and_selection():
def layer_container_and_selection():
"""
Create a container and a dropdown widget to select the labels layer.
Create a container and a dropdown widget to select the layer.
Returns
-------
A tuple containing a QWidget for displaying the labels layer selection container,
and a QWidget containing the selection options for the labels layer.
A tuple containing a QWidget for displaying the layer selection container,
and a QWidget containing the selection options for the layer.
"""
labels_layer_selection_container = QWidget()
labels_layer_selection_container.setLayout(QHBoxLayout())
labels_layer_selection_container.layout().addWidget(QLabel("Labels layer"))
labels_select = create_widget(annotation=Labels, label="labels_layer")
labels_layer_selection_container.layout().addWidget(labels_select.native)
layer_selection_container = QWidget()
layer_selection_container.setLayout(QHBoxLayout())
layer_selection_container.layout().addWidget(QLabel("Layer"))
layer_select = create_widget(annotation=Layer, label="layer")
layer_selection_container.layout().addWidget(layer_select.native)

return labels_layer_selection_container, labels_select
return layer_selection_container, layer_select


def image_container_and_selection():
Expand Down Expand Up @@ -528,6 +528,8 @@ def __init__(self, parent=None, width=7, height=4, manual_clustering_method=None
self.match_napari_layout()
self.xylim = None
self.last_xy_labels = None
self.last_datax = None
self.last_datay = None

super().__init__(self.fig)
self.mpl_connect("draw_event", self.on_draw)
Expand Down Expand Up @@ -590,7 +592,17 @@ def make_2d_histogram(
norm = None
if log_scale:
norm = "log"
h, xedges, yedges = np.histogram2d(data_x, data_y, bins=bin_number)
if (
self.histogram is not None
and np.array_equal(self.last_datax, data_x)
and np.array_equal(self.last_datay, data_y)
):
(h, xedges, yedges) = self.histogram
else:
h, xedges, yedges = np.histogram2d(data_x, data_y, bins=bin_number)
self.last_datax = data_x
self.last_datay = data_y

self.axes.imshow(
h.T,
extent=[xedges[0], xedges[-1], yedges[0], yedges[-1]],
Expand Down
43 changes: 15 additions & 28 deletions napari_clusters_plotter/_clustering.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
from napari_tools_menu import register_dock_widget
from qtpy.QtWidgets import QHBoxLayout, QLabel, QLineEdit, QVBoxLayout, QWidget

from ._defaults import DEFAULTS_CLUSTERING as DEFAULTS
from ._defaults import ID_NAME
from ._Qt_code import (
button,
checkbox,
create_options_dropdown,
float_sbox_containter_and_selection,
int_sbox_containter_and_selection,
labels_container_and_selection,
layer_container_and_selection,
measurements_container_and_list,
title,
)
Expand All @@ -30,21 +32,6 @@
widgets_active,
)

DEFAULTS = {
"kmeans_nr_clusters": 2,
"kmeans_nr_iterations": 300,
"standardization": False,
"hdbscan_min_clusters_size": 5,
"hdbscan_min_nr_samples": 5,
"gmm_nr_clusters": 2,
"ms_quantile": 0.2,
"ms_n_samples": 50,
"ac_n_clusters": 2,
"ac_n_neighbors": 2,
"custom_name": "",
}
ID_NAME = "_CLUSTER_ID"


@register_dock_widget(menu="Measurement post-processing > Clustering (ncp)")
class ClusteringWidget(QWidget):
Expand All @@ -64,11 +51,11 @@ def __init__(self, napari_viewer):

title_container = title("<b>Clustering</b>")

# widget for the selection of labels layer
# widget for the selection of layer
(
labels_layer_selection_container,
self.labels_select,
) = labels_container_and_selection()
layer_selection_container,
self.layer_select,
) = layer_container_and_selection()

# widget for the selection of properties to perform clustering
(
Expand Down Expand Up @@ -215,7 +202,7 @@ def __init__(self, napari_viewer):

# adding all widgets to the layout
self.layout().addWidget(title_container)
self.layout().addWidget(labels_layer_selection_container)
self.layout().addWidget(layer_selection_container)
self.layout().addWidget(choose_properties_container)
self.layout().addWidget(update_container)
self.layout().addWidget(self.clust_method_container)
Expand All @@ -235,7 +222,7 @@ def __init__(self, napari_viewer):
self.layout().setSpacing(0)

def run_clicked():
if self.labels_select.value is None:
if self.layer_select.value is None:
warnings.warn("No labels image was selected!")
return

Expand All @@ -248,7 +235,7 @@ def run_clicked():
return

self.run(
self.labels_select.value,
self.layer_select.value,
[i.text() for i in self.properties_list.selectedItems()],
self.clust_method_choice_list.current_choice,
self.kmeans_nr_clusters.value,
Expand All @@ -271,14 +258,14 @@ def run_clicked():
self.defaults_button.clicked.connect(partial(restore_defaults, self, DEFAULTS))

# update measurements list when a new labels layer is selected
self.labels_select.changed.connect(
self.layer_select.changed.connect(
partial(update_properties_list, self, [ID_NAME])
)

# update axes combo boxes automatically if features of
# layer are changed
self.last_connected = None
self.labels_select.changed.connect(self.activate_property_autoupdate)
self.layer_select.changed.connect(self.activate_property_autoupdate)

# go through all widgets and change spacing
for i in range(self.layout().count()):
Expand Down Expand Up @@ -343,17 +330,17 @@ def activate_property_autoupdate(self):
self.last_connected.events.properties.disconnect(
partial(update_properties_list, self, [ID_NAME])
)
self.labels_select.value.events.properties.connect(
self.layer_select.value.events.properties.connect(
partial(update_properties_list, self, [ID_NAME])
)
self.last_connected = self.labels_select.value
self.last_connected = self.layer_select.value

def showEvent(self, event) -> None:
super().showEvent(event)
self.reset_choices()

def reset_choices(self, event=None):
self.labels_select.reset_choices(event)
self.layer_select.reset_choices(event)

# this function runs after the run button is clicked
def run(
Expand Down
36 changes: 36 additions & 0 deletions napari_clusters_plotter/_defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
DEFAULTS_CLUSTERING = {
"kmeans_nr_clusters": 2,
"kmeans_nr_iterations": 300,
"standardization": False,
"hdbscan_min_clusters_size": 5,
"hdbscan_min_nr_samples": 5,
"gmm_nr_clusters": 2,
"ms_quantile": 0.2,
"ms_n_samples": 50,
"ac_n_clusters": 2,
"ac_n_neighbors": 2,
"custom_name": "",
}

DEFAULTS_DIM_REDUCTION = {
"n_neighbors": 15,
"perplexity": 30,
"standardization": True,
"pca_components": 0,
"explained_variance": 95.0,
"n_components": 2,
# enabling multithreading for UMAP can result in crashing kernel if napari is opened from the Jupyter notebook,
# therefore by default the following value is False.
# See more: https://github.com/BiAPoL/napari-clusters-plotter/issues/169
"umap_separate_thread": False,
"min_distance_umap": 0.1,
"mds_n_init": 4,
"mds_metric": True,
"mds_max_iter": 300,
"mds_eps": 0.001,
"custom_name": "",
}

ID_NAME = "_CLUSTER_ID"
_POINTER = "frame"
EXCLUDE = [ID_NAME, _POINTER, "UMAP", "t-SNE", "PCA"]
Loading

0 comments on commit 779cac0

Please sign in to comment.