Skip to content

Commit 1eac502

Browse files
authored
Merge pull request #385 from BiAPoL/v0.9.0_support_tracking_layer
Support tracking data
2 parents e64101a + 3b1cb70 commit 1eac502

File tree

15 files changed

+6301
-17
lines changed

15 files changed

+6301
-17
lines changed

napari_clusters_plotter/tgmm-mini-spot.csv

Lines changed: 3088 additions & 0 deletions
Large diffs are not rendered by default.

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ dependencies = [
4040
"napari-skimage-regionprops>=0.3.1",
4141
"scikit-image",
4242
"scipy",
43-
"biaplotter>=0.2.0"
43+
"biaplotter>=0.2.0",
44+
"imagecodecs"
4445
]
4546

4647

src/napari_clusters_plotter/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
DimensionalityReductionWidget,
66
)
77
from ._new_plotter_widget import PlotterWidget
8-
from ._sample_data import bbbc_1_dataset, cells3d_curvatures
8+
from ._sample_data import bbbc_1_dataset, cells3d_curvatures, tgmm_mini_dataset
99

1010
__all__ = [
1111
"PlotterWidget",
1212
"DimensionalityReductionWidget",
1313
"ClusteringWidget",
1414
"bbbc_1_dataset",
15+
"tgmm_mini_dataset",
1516
"cells3d_curvatures",
1617
]

src/napari_clusters_plotter/_algorithm_widget.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
Points,
88
Shapes,
99
Surface,
10+
Tracks,
1011
Vectors,
1112
)
1213
from qtpy.QtWidgets import (
@@ -21,13 +22,7 @@
2122

2223
class BaseWidget(QWidget):
2324

24-
input_layer_types = [
25-
Labels,
26-
Points,
27-
Surface,
28-
Vectors,
29-
Shapes,
30-
]
25+
input_layer_types = [Labels, Points, Surface, Vectors, Shapes, Tracks]
3126

3227
def __init__(self, napari_viewer):
3328
super().__init__()

src/napari_clusters_plotter/_new_plotter_widget.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,14 +372,30 @@ def _on_update_layer_selection(
372372
self._update_feature_selection(None)
373373

374374
for layer in self.layers:
375-
layer.events.features.connect(self._update_feature_selection)
375+
event_attr = getattr(layer.events, "features", None) or getattr(
376+
layer.events, "properties", None
377+
)
378+
if event_attr:
379+
event_attr.connect(self._update_feature_selection)
380+
else:
381+
Warning(
382+
f"Layer {layer.name} does not have events.features or events.properties"
383+
)
376384

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

380388
# disconnect the events from the layers
381389
for layer in self.viewer.layers.selection:
382-
layer.events.features.disconnect(self._update_feature_selection)
390+
event_attr = getattr(layer.events, "features", None) or getattr(
391+
layer.events, "properties", None
392+
)
393+
if event_attr:
394+
event_attr.disconnect(self._update_feature_selection)
395+
else:
396+
Warning(
397+
f"Layer {layer.name} does not have events.features or events.properties"
398+
)
383399

384400
# reset the selected layers
385401
self.layers = []
@@ -512,6 +528,10 @@ def _apply_layer_color(layer, colors):
512528
elif isinstance(layer, napari.layers.Shapes):
513529
layer.face_color = colors
514530

531+
elif isinstance(layer, napari.layers.Tracks):
532+
layer._track_colors = colors
533+
layer.events.color_by()
534+
515535
elif isinstance(layer, napari.layers.Labels):
516536

517537
colors = np.insert(colors, 0, [0, 0, 0, 0], axis=0)

src/napari_clusters_plotter/_sample_data.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,41 @@
44
from typing import List
55

66

7+
def tgmm_mini_dataset() -> List["LayerData"]: # noqa: F821
8+
import pandas as pd
9+
from skimage.io import imread
10+
11+
path = Path(__file__).parent / "sample_data" / "tracking_data"
12+
data = pd.read_csv(path / Path("tgmm-mini-tracks-layer-data.csv"))
13+
features = pd.read_csv(
14+
path / Path("tgmm-mini-spot.csv"),
15+
skiprows=[1, 2],
16+
low_memory=False,
17+
encoding="utf-8",
18+
)
19+
tracking_label_image = imread(path / Path("tgmm-mini.tif"))
20+
21+
layer_data_tuple_tracks = (
22+
data,
23+
{
24+
"name": "tgmm-mini-tracks",
25+
"features": features,
26+
},
27+
"tracks",
28+
)
29+
30+
layer_data_tuple_labels = (
31+
tracking_label_image,
32+
{
33+
"name": "tgmm-mini-labels",
34+
"features": features,
35+
},
36+
"labels",
37+
)
38+
39+
return [layer_data_tuple_tracks, layer_data_tuple_labels]
40+
41+
742
def bbbc_1_dataset() -> List["LayerData"]: # noqa: F821
843
import numpy as np
944
import pandas as pd
@@ -78,8 +113,9 @@ def cells3d_curvatures() -> List["LayerData"]: # noqa: F821
78113
(vertices, faces),
79114
{
80115
"name": "cells_3d_mitotic_nucleus_surface_curvatures",
81-
'features': hks,},
82-
"surface",
116+
"features": hks,
117+
},
118+
"surface",
83119
]
84120

85121
layer_data_nuclei = (

src/napari_clusters_plotter/_tests/test_plotter.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,38 @@ def create_multi_point_layer(n_samples: int = 100):
8181
return layer, layer2
8282

8383

84+
def create_multi_tracks_layer(n_samples: int = 100):
85+
from napari.layers import Tracks
86+
87+
points1, points2 = create_multi_point_layer(n_samples=n_samples)
88+
89+
tracks1 = points1.data.copy()
90+
tracks2 = points2.data.copy()
91+
92+
# insert empty track id column
93+
tracks1 = np.insert(tracks1, 0, 0, axis=1)
94+
tracks2 = np.insert(tracks2, 0, 0, axis=1)
95+
96+
for t in range(int(points1.data[:, 0].max() + 1)):
97+
# set the track id for each point
98+
tracks1[tracks1[:, 1] == t, 0] = np.arange(
99+
len(tracks1[tracks1[:, 1] == t]), dtype=int
100+
)
101+
102+
for t in range(int(points2.data[:, 0].max() + 1)):
103+
# set the track id for each point
104+
tracks2[tracks2[:, 1] == t, 0] = np.arange(
105+
len(tracks2[tracks2[:, 1] == t]), dtype=int
106+
)
107+
108+
tracks1 = Tracks(tracks1, features=points1.features, name="tracks1")
109+
tracks2 = Tracks(
110+
tracks2, features=points2.features, name="tracks2", translate=(0, 0, 2)
111+
)
112+
113+
return tracks1, tracks2
114+
115+
84116
def create_multi_vectors_layer(n_samples: int = 100):
85117
from napari.layers import Vectors
86118

@@ -258,6 +290,7 @@ def test_mixed_layers(make_napari_viewer):
258290
create_multi_vectors_layer,
259291
create_multi_surface_layer,
260292
create_multi_shapes_layers,
293+
create_multi_tracks_layer,
261294
],
262295
)
263296
def test_cluster_memorization(make_napari_viewer, create_sample_layers):
@@ -318,6 +351,7 @@ def test_multiscale_plotter(make_napari_viewer):
318351
create_multi_vectors_layer,
319352
create_multi_surface_layer,
320353
create_multi_shapes_layers,
354+
create_multi_tracks_layer,
321355
],
322356
)
323357
def test_categorical_handling(make_napari_viewer, create_sample_layers):

src/napari_clusters_plotter/_tests/test_sample_data.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@
33
from napari_clusters_plotter._sample_data import (
44
bbbc_1_dataset,
55
cells3d_curvatures,
6+
tgmm_mini_dataset,
67
)
78

89

910
@pytest.mark.parametrize(
1011
"sample_data_function",
11-
[
12-
bbbc_1_dataset,
13-
cells3d_curvatures,
14-
],
12+
[bbbc_1_dataset, cells3d_curvatures, tgmm_mini_dataset],
1513
)
1614
def test_bbbc_1_sample_data(make_napari_viewer, sample_data_function):
1715
from napari.layers import Layer

src/napari_clusters_plotter/napari.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ contributions:
2121
python_name: napari_clusters_plotter:cells3d_curvatures
2222
title: Load cells3d mitotic nucleus surface curvatures
2323

24+
- id: napari-clusters-plotter.tgmm_mini_data
25+
python_name: napari_clusters_plotter:tgmm_mini_dataset
26+
title: Load tgmm mini dataset
27+
2428
menus:
2529
napari/layers/visualize:
2630
- submenu: features_submenu
@@ -47,6 +51,9 @@ contributions:
4751
- command: napari-clusters-plotter.bbbc_sample_data
4852
key: bbbc1
4953
display_name: BBBC 1 dataset & segmentations
54+
- command: napari-clusters-plotter.tgmm_mini_data
55+
key: tgmm_mini
56+
display_name: TGMM mini dataset (tracks and segmentations)
5057
- command: napari-clusters-plotter.cells3d_curvatures
5158
key: cells3d_curvatures
5259
display_name: Cells3D mitotic nucleus surface curvatures
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Janelia Open-Source Software
2+
Copyright © 2018 Howard Hughes Medical Institute
3+
4+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5+
6+
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7+
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8+
Neither the name of HHMI nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

0 commit comments

Comments
 (0)