Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
1c58e12
added test for cluster memorization
jo-mueller Jan 29, 2025
10317f2
merged `get_data` function into `_replot function`
jo-mueller Jan 30, 2025
deb5089
merged `_get_data` function
jo-mueller Jan 30, 2025
1bd7d16
added `MANUAL_CLUSTER_ID` as feature to memorize a previous selection
jo-mueller Jan 30, 2025
402fff1
more explicit layer naming in test
jo-mueller Jan 30, 2025
f71382d
made point clouds of uneven size
jo-mueller Jan 30, 2025
d78de0c
used layers of uneven size in demo notebook
jo-mueller Jan 30, 2025
13e9ff2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 30, 2025
70723bf
return 'MANUAL_CLUSTER_ID' with all features and avoid adding to dro…
jo-mueller Jan 30, 2025
ea89793
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 30, 2025
756abe7
remove `MANUAL_CLUSTER_ID` only if it exists
jo-mueller Jan 30, 2025
cfd3b87
Merge branch 'fix-cluster-memorization' of https://github.com/BiAPoL/…
jo-mueller Jan 30, 2025
32f947a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 30, 2025
4c73c34
fixed adding features to dropdown
jo-mueller Jan 30, 2025
e16721e
Merge branch 'fix-cluster-memorization' of https://github.com/BiAPoL/…
jo-mueller Jan 30, 2025
7243c30
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 30, 2025
1a792f4
add a wait for update in test
jo-mueller Jan 30, 2025
b83d29b
Revert "add a wait for update in test"
jo-mueller Jan 30, 2025
aaf8f98
set biaplotter dependency to git repo for latest version
jo-mueller Feb 4, 2025
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
261 changes: 243 additions & 18 deletions notebooks/demo_new_plotter.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,7 @@
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"napari.manifest -> 'napari-vedo-bridge' could not be imported: The name field in the manifest ('napari-clusters-plotter') must match the package name ('napari-vedo-bridge')\n"
]
}
],
"outputs": [],
"source": [
"viewer = napari.Viewer()"
]
Expand All @@ -46,7 +38,7 @@
{
"data": {
"text/plain": [
"<Points layer 'points2' at 0x204f46b5c10>"
"<Points layer 'points2' at 0x12998840130>"
]
},
"execution_count": 3,
Expand All @@ -63,10 +55,10 @@
"frame = np.arange(n_timeframes).repeat(n_samples//n_timeframes)\n",
"# make some random points with random features\n",
"points = np.random.random((n_samples, 4))\n",
"points2 = np.random.random((n_samples, 4))\n",
"points2 = np.random.random((n_samples-1, 4))\n",
"\n",
"points[:, 0] = frame\n",
"points2[:, 0] = frame\n",
"points2[:, 0] = frame[:-1]\n",
"\n",
"features = pd.DataFrame({\n",
" 'frame': frame,\n",
Expand All @@ -76,13 +68,14 @@
" 'feature4': np.random.normal(size=n_samples, loc=loc),})\n",
"\n",
"features2 = pd.DataFrame({\n",
" 'frame': frame,\n",
" 'feature2': np.random.normal(size=n_samples, loc=-loc),\n",
" 'feature3': np.random.normal(size=n_samples, loc=-loc),\n",
" 'feature4': np.random.normal(size=n_samples, loc=-loc),})\n",
" 'frame': frame[:-1],\n",
" 'feature2': np.random.normal(size=n_samples-1, loc=-loc),\n",
" 'feature3': np.random.normal(size=n_samples-1, loc=-loc),\n",
" 'feature4': np.random.normal(size=n_samples-1, loc=-loc),})\n",
"\n",
"layer = napari.layers.Points(points, features=features, size=0.1, blending='translucent_no_depth')\n",
"layer2 = napari.layers.Points(points2, features=features2, size=0.1, translate=(0, 0, 2), blending='translucent_no_depth')\n",
"viewer.layers.clear()\n",
"viewer.add_layer(layer)\n",
"viewer.add_layer(layer2)\n"
]
Expand All @@ -105,7 +98,7 @@
{
"data": {
"text/plain": [
"<napari._qt.widgets.qt_viewer_dock_widget.QtViewerDockWidget at 0x2049456d3a0>"
"<napari._qt.widgets.qt_viewer_dock_widget.QtViewerDockWidget at 0x1299a10a820>"
]
},
"execution_count": 4,
Expand All @@ -118,6 +111,238 @@
"viewer.window.add_dock_widget(plotter_widget, area='right')"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>frame</th>\n",
" <th>feature2</th>\n",
" <th>feature3</th>\n",
" <th>feature4</th>\n",
" <th>MANUAL_CLUSTER_ID</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0</td>\n",
" <td>-4.725088</td>\n",
" <td>-4.325642</td>\n",
" <td>-7.112442</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>0</td>\n",
" <td>-4.386041</td>\n",
" <td>-5.335577</td>\n",
" <td>-6.063437</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>0</td>\n",
" <td>-5.730792</td>\n",
" <td>-4.642161</td>\n",
" <td>-4.429953</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>0</td>\n",
" <td>-6.089492</td>\n",
" <td>-2.991715</td>\n",
" <td>-5.544447</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>0</td>\n",
" <td>-4.740159</td>\n",
" <td>-5.189429</td>\n",
" <td>-4.769790</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>94</th>\n",
" <td>4</td>\n",
" <td>-5.815555</td>\n",
" <td>-4.737373</td>\n",
" <td>-4.945831</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>95</th>\n",
" <td>4</td>\n",
" <td>-6.226173</td>\n",
" <td>-3.972162</td>\n",
" <td>-6.477352</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96</th>\n",
" <td>4</td>\n",
" <td>-4.597238</td>\n",
" <td>-3.308072</td>\n",
" <td>-4.418548</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>97</th>\n",
" <td>4</td>\n",
" <td>-6.143753</td>\n",
" <td>-5.130647</td>\n",
" <td>-5.700410</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>98</th>\n",
" <td>4</td>\n",
" <td>-4.029651</td>\n",
" <td>-5.172430</td>\n",
" <td>-5.987246</td>\n",
" <td>1</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>99 rows × 5 columns</p>\n",
"</div>"
],
"text/plain": [
" frame feature2 feature3 feature4 MANUAL_CLUSTER_ID\n",
"0 0 -4.725088 -4.325642 -7.112442 1\n",
"1 0 -4.386041 -5.335577 -6.063437 1\n",
"2 0 -5.730792 -4.642161 -4.429953 1\n",
"3 0 -6.089492 -2.991715 -5.544447 0\n",
"4 0 -4.740159 -5.189429 -4.769790 1\n",
".. ... ... ... ... ...\n",
"94 4 -5.815555 -4.737373 -4.945831 0\n",
"95 4 -6.226173 -3.972162 -6.477352 0\n",
"96 4 -4.597238 -3.308072 -4.418548 0\n",
"97 4 -6.143753 -5.130647 -5.700410 0\n",
"98 4 -4.029651 -5.172430 -5.987246 1\n",
"\n",
"[99 rows x 5 columns]"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"viewer.layers[-1].features"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(99, 4)"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"viewer.layers[1].data.shape"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0,\n",
" 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0,\n",
" 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1,\n",
" 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0])"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"viewer.layers.selection.active = viewer.layers[-1]\n",
"plotter_widget._selectors['x'].setCurrentText('feature3')\n",
"plotter_widget.plotting_widget.active_artist.color_indices = np.random.randint(0, 2, n_samples)\n",
"plotter_widget.plotting_widget.active_artist.color_indices"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0,\n",
" 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0,\n",
" 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1,\n",
" 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0])"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"viewer.layers.selection.active = viewer.layers[0]\n",
"plotter_widget.plotting_widget.active_artist.color_indices"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 6,
Expand Down Expand Up @@ -377,7 +602,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.19"
"version": "3.9.18"
}
},
"nbformat": 4,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ dependencies = [
"scikit-image",
"superqt",
"scipy",
"biaplotter"
"biaplotter@https://github.com/BiAPoL/biaplotter/archive/refs/heads/main.zip"
]


Expand Down
47 changes: 28 additions & 19 deletions src/napari_clusters_plotter/_new_plotter_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,24 @@ def _replot(self):
if self.x_axis == "" or self.y_axis == "":
return

data_to_plot = self._get_data()
self.plotting_widget.active_artist.data = data_to_plot
# retrieve the data from the selected layers
features = self._get_features()
x_data = features[self.x_axis].values
y_data = features[self.y_axis].values

# # if no hue is selected, set it to 0
# if self.hue_axis == "None":
# hue = np.zeros(len(features))
# elif self.hue_axis != "":
# hue = features[self.hue_axis].values

self.plotting_widget.active_artist.data = np.stack(
[x_data, y_data], axis=1
)
if "MANUAL_CLUSTER_ID" in features.columns:
self.plotting_widget.active_artist.color_indices = features[
"MANUAL_CLUSTER_ID"
].values

def _checkbox_status_changed(self):
self._replot()
Expand Down Expand Up @@ -264,22 +280,6 @@ def n_selected_layers(self) -> int:
"""
return len(list(self.viewer.layers.selection))

def _get_data(self) -> np.ndarray:
"""
Get the data from the selected layers features.
"""
features = self._get_features()
x_data = features[self.x_axis].values
y_data = features[self.y_axis].values

# # if no hue is selected, set it to 0
# if self.hue_axis == "None":
# hue = np.zeros(len(features))
# elif self.hue_axis != "":
# hue = features[self.hue_axis].values

return np.stack([x_data, y_data], axis=1)

def _on_update_layer_selection(
self, event: napari.utils.events.Event
) -> None:
Expand Down Expand Up @@ -327,7 +327,11 @@ def _update_feature_selection(
self._selectors[dim].clear()

for dim in ["x", "y", "hue"]:
self._selectors[dim].addItems(sorted(self.common_columns))
features_to_add = sorted(self.common_columns)
if "MANUAL_CLUSTER_ID" in features_to_add:
features_to_add.remove("MANUAL_CLUSTER_ID")

self._selectors[dim].addItems(features_to_add)

# it should always be possible to select no color
self._selectors["hue"].addItem("None")
Expand Down Expand Up @@ -361,6 +365,11 @@ def _color_layer_by_cluster_id(self):
].index
_apply_layer_color(selected_layer, colors[layer_indices])

# store cluster indeces in the features table
selected_layer.features["MANUAL_CLUSTER_ID"] = color_indices[
layer_indices
]

def _reset(self):
"""
Reset the selection in the current plotting widget.
Expand Down
Loading