From bf09d794596de073a993f5e8c942782bb1a42ff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20M=C3=BCller?= <38459088+jo-mueller@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:42:33 +0200 Subject: [PATCH 01/11] added test for 4D points layer --- .../_tests/test_plotter.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/napari_clusters_plotter/_tests/test_plotter.py b/napari_clusters_plotter/_tests/test_plotter.py index b7004f79..8b05df90 100644 --- a/napari_clusters_plotter/_tests/test_plotter.py +++ b/napari_clusters_plotter/_tests/test_plotter.py @@ -232,6 +232,45 @@ def test_plotter_on_points_data(make_napari_viewer): ) +def test_plotter_on_points_data4d(make_napari_viewer): + from napari_clusters_plotter._plotter import PlotterWidget + from napari_clusters_plotter._utilities import get_layer_tabular_data + + viewer = make_napari_viewer() + n_points = 100 + n_timepoints = 2 + points = np.random.rand(n_points, 4) + points[:, 0] = np.arange(0, n_timepoints).repeat(n_points // n_timepoints) + + feature1 = np.random.normal(size=n_points) + feature2 = np.random.normal(size=n_points, loc=1) + annotations = 1 * (np.random.uniform(size=100) > 0.5) + + viewer.add_points(points, properties={"feature1": feature1, "feature2": feature2, 'frame': points[:, 0]}, size=0.1) + + widget = PlotterWidget(viewer) + viewer.window.add_dock_widget(widget) + + # Put the points layer into the layer selection widget + widget.analysed_layer = viewer.layers[0] + widget.plot_x_axis.setCurrentText("feature1") + widget.plot_y_axis.setCurrentText("feature2") + widget.analysed_layer.features["MANUAL_CLUSTER_ID"] = annotations + + # check that the features are found + features = get_layer_tabular_data(widget.analysed_layer) + assert "feature1" in features.columns + assert "feature2" in features.columns + + widget.run( + widget.analysed_layer.features, + plot_x_axis_name="feature1", + plot_y_axis_name="feature2", + plot_cluster_name="MANUAL_CLUSTER_ID", + force_redraw=True, + ) + + def test_plotter_on_surface_data(make_napari_viewer): from napari_clusters_plotter._plotter import PlotterWidget from napari_clusters_plotter._utilities import get_layer_tabular_data From 9cf67049d4222163e2f9c08f4c46778eddb52729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20M=C3=BCller?= <38459088+jo-mueller@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:55:24 +0200 Subject: [PATCH 02/11] added test for 4d surface --- .../_tests/test_plotter.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/napari_clusters_plotter/_tests/test_plotter.py b/napari_clusters_plotter/_tests/test_plotter.py index 8b05df90..794042ce 100644 --- a/napari_clusters_plotter/_tests/test_plotter.py +++ b/napari_clusters_plotter/_tests/test_plotter.py @@ -311,6 +311,53 @@ def test_plotter_on_surface_data(make_napari_viewer): ) +def test_plotter_on_surface_data4d(make_napari_viewer): + + from napari_clusters_plotter._plotter import PlotterWidget + + viewer = make_napari_viewer() + n_points = 100 + n_timepoints = 2 + vertices = np.random.rand(n_points, 4) + vertices[:, 0] = np.arange(0, n_timepoints).repeat(n_points // n_timepoints) + + # Create a random mesh + faces_t0 = np.random.randint(0, 49, (100, 3)) + faces_t1 = np.random.randint(50, 99, (100, 3)) + faces = np.concatenate((faces_t0, faces_t1)) + + feature1 = np.random.normal(size=n_points) + feature2 = np.random.normal(size=n_points, loc=1) + annotations = 1 * (np.random.uniform(size=n_points) > 0.5) + surface_tuple = (vertices, faces) + + # need to add features later-on as napari currently doesn't support features for surfaces + layer = viewer.add_surface(surface_tuple, name='random_mesh') + layer.features = pd.DataFrame({'feature1': feature1, 'feature2': feature2, 'frame': vertices[:, 0], 'annotations': annotations}) + + widget = PlotterWidget(viewer) + viewer.window.add_dock_widget(widget) + + # Put the points layer into the layer selection widget + widget.analysed_layer = viewer.layers[0] + widget.plot_x_axis.setCurrentText("feature1") + widget.plot_y_axis.setCurrentText("feature2") + widget.analysed_layer.features["MANUAL_CLUSTER_ID"] = annotations + + # check that the features are found + features = get_layer_tabular_data(widget.analysed_layer) + assert "feature1" in features.columns + assert "feature2" in features.columns + + widget.run( + widget.analysed_layer.features, + plot_x_axis_name="feature1", + plot_y_axis_name="feature2", + plot_cluster_name="MANUAL_CLUSTER_ID", + force_redraw=True, + ) + + def test_cluster_image_generation_for_histogram(make_napari_viewer): from napari_clusters_plotter._plotter import PlotterWidget From f487a9edbdac17cb4c7d8e093b48662cf2ee2bfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20M=C3=BCller?= <38459088+jo-mueller@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:55:58 +0200 Subject: [PATCH 03/11] added missing lazy import --- napari_clusters_plotter/_tests/test_plotter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/napari_clusters_plotter/_tests/test_plotter.py b/napari_clusters_plotter/_tests/test_plotter.py index 794042ce..780d7ecc 100644 --- a/napari_clusters_plotter/_tests/test_plotter.py +++ b/napari_clusters_plotter/_tests/test_plotter.py @@ -314,6 +314,7 @@ def test_plotter_on_surface_data(make_napari_viewer): def test_plotter_on_surface_data4d(make_napari_viewer): from napari_clusters_plotter._plotter import PlotterWidget + from napari_clusters_plotter._utilities import get_layer_tabular_data viewer = make_napari_viewer() n_points = 100 From d28dce32e7bbb3fc784cc0e3ade2f6514e6db759 Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Tue, 23 Apr 2024 16:20:56 +0200 Subject: [PATCH 04/11] add tests for 3d data, 3d timelapse, 2d timelapse, 2d tracking, 3d tracking --- .../_tests/test_plotter.py | 205 +++++++++++++++++- 1 file changed, 204 insertions(+), 1 deletion(-) diff --git a/napari_clusters_plotter/_tests/test_plotter.py b/napari_clusters_plotter/_tests/test_plotter.py index 780d7ecc..9d45800c 100644 --- a/napari_clusters_plotter/_tests/test_plotter.py +++ b/napari_clusters_plotter/_tests/test_plotter.py @@ -36,7 +36,7 @@ def get_labels_array(): return label -def test_plotting(make_napari_viewer): +def test_plotter_on_labels2d(make_napari_viewer): viewer = make_napari_viewer() widget_list = ncp.napari_experimental_provide_dock_widget() @@ -78,6 +78,209 @@ def test_plotting(make_napari_viewer): print("check") +def test_plotter_on_labels3d(make_napari_viewer): + from napari_clusters_plotter._plotter import PlotterWidget + from napari_clusters_plotter._utilities import get_layer_tabular_data + + viewer = make_napari_viewer() + # Generate 3D data + z_slices = 3 + n_labels = get_labels_array().max() + data_3d = np.stack([get_labels_array() for _ in range(z_slices)]) + # Create some random features + label_column = np.arange(1, n_labels+1) + feature1 = np.random.normal(size=n_labels) + feature2 = np.random.normal(size=n_labels, loc=1) + annotations = 1 * (np.random.uniform(size=n_labels) > 0.5) + + viewer.add_labels(data_3d, properties={"label": label_column, "feature1": feature1, "feature2": feature2, "annotations": annotations}) + + widget = PlotterWidget(viewer) + viewer.window.add_dock_widget(widget) + + # Put the labels layer into the layer selection widget + widget.analysed_layer = viewer.layers[0] + widget.plot_x_axis.setCurrentText("feature1") + widget.plot_y_axis.setCurrentText("feature2") + widget.analysed_layer.features["MANUAL_CLUSTER_ID"] = annotations + + # check that the features are found + features = get_layer_tabular_data(widget.analysed_layer) + assert "feature1" in features.columns + assert "feature2" in features.columns + + widget.run( + widget.analysed_layer.features, + plot_x_axis_name="feature1", + plot_y_axis_name="feature2", + plot_cluster_name="MANUAL_CLUSTER_ID", + force_redraw=True, + ) + +def test_plotter_on_labels2d_timelapse(make_napari_viewer): + from napari_clusters_plotter._plotter import PlotterWidget + from napari_clusters_plotter._utilities import get_layer_tabular_data + + viewer = make_napari_viewer() + # Generate 2D timelapse data + n_timepoints = 2 + n_labels = get_labels_array().max() + data_2d_timelapse = np.array([np.roll(get_labels_array(), t, axis=0) for t in range(n_timepoints)]) + data_2d_timelapse = np.expand_dims(data_2d_timelapse, axis=1) # add unidimensional z axis + # Create some random features + label_column = np.tile(np.arange(1, n_labels+1), n_timepoints) + feature1 = np.random.normal(size=n_labels*n_timepoints) + feature2 = np.random.normal(size=n_labels*n_timepoints, loc=1) + annotations = 1 * (np.random.uniform(size=n_labels*n_timepoints) > 0.5) + frame = np.arange(0, n_timepoints).repeat(n_labels) # add frame column for timelapsed data + + viewer.add_labels(data_2d_timelapse, properties={"label": label_column, "feature1": feature1, "feature2": feature2, "annotations": annotations, "frame": frame}) + + widget = PlotterWidget(viewer) + viewer.window.add_dock_widget(widget) + + # Put the labels layer into the layer selection widget + widget.analysed_layer = viewer.layers[0] + widget.plot_x_axis.setCurrentText("feature1") + widget.plot_y_axis.setCurrentText("feature2") + widget.analysed_layer.features["MANUAL_CLUSTER_ID"] = annotations + + # check that the features are found + features = get_layer_tabular_data(widget.analysed_layer) + assert "feature1" in features.columns + assert "feature2" in features.columns + + widget.run( + widget.analysed_layer.features, + plot_x_axis_name="feature1", + plot_y_axis_name="feature2", + plot_cluster_name="MANUAL_CLUSTER_ID", + force_redraw=True, + ) + +def test_plotter_on_labels3d_timelapse(make_napari_viewer): + from napari_clusters_plotter._plotter import PlotterWidget + from napari_clusters_plotter._utilities import get_layer_tabular_data + + viewer = make_napari_viewer() + # Generate 3D timelapse data + z_slices = 3 + n_timepoints = 2 + n_labels = get_labels_array().max() + data_3d_timelapse = np.array([np.roll(np.stack([get_labels_array() for _ in range(z_slices)]), t, axis=1) for t in range(n_timepoints)]) + # Create some random features + label_column = np.tile(np.arange(1, n_labels+1), n_timepoints) + feature1 = np.random.normal(size=n_labels*n_timepoints) + feature2 = np.random.normal(size=n_labels*n_timepoints, loc=1) + annotations = 1 * (np.random.uniform(size=n_labels*n_timepoints) > 0.5) + frame = np.arange(0, n_timepoints).repeat(n_labels) # add frame column for timelapsed data + + viewer.add_labels(data_3d_timelapse, properties={"label": label_column, "feature1": feature1, "feature2": feature2, "annotations": annotations, "frame": frame}) + + widget = PlotterWidget(viewer) + viewer.window.add_dock_widget(widget) + + # Put the labels layer into the layer selection widget + widget.analysed_layer = viewer.layers[0] + widget.plot_x_axis.setCurrentText("feature1") + widget.plot_y_axis.setCurrentText("feature2") + widget.analysed_layer.features["MANUAL_CLUSTER_ID"] = annotations + + # check that the features are found + features = get_layer_tabular_data(widget.analysed_layer) + assert "feature1" in features.columns + assert "feature2" in features.columns + + widget.run( + widget.analysed_layer.features, + plot_x_axis_name="feature1", + plot_y_axis_name="feature2", + plot_cluster_name="MANUAL_CLUSTER_ID", + force_redraw=True, + ) + +def test_plotter_on_labels2d_tracking(make_napari_viewer): + from napari_clusters_plotter._plotter import PlotterWidget + from napari_clusters_plotter._utilities import get_layer_tabular_data + + viewer = make_napari_viewer() + # Generate 2D tracking data + n_timepoints = 2 + n_labels = get_labels_array().max() + data_2d_tracking = np.array([np.roll(get_labels_array(), t, axis=0) for t in range(n_timepoints)]) + data_2d_tracking = np.expand_dims(data_2d_tracking, axis=1) # add unidimensional z axis + # Create some random features + label_column = np.arange(1, n_labels+1) + feature1 = np.random.normal(size=n_labels) + feature2 = np.random.normal(size=n_labels, loc=1) + annotations = 1 * (np.random.uniform(size=n_labels) > 0.5) + # Note how there is no frame column for tracking data, because we are analyzing features for the whole tracks + + viewer.add_labels(data_2d_tracking, properties={"label": label_column, "feature1": feature1, "feature2": feature2, "annotations": annotations}) + + widget = PlotterWidget(viewer) + viewer.window.add_dock_widget(widget) + + # Put the labels layer into the layer selection widget + widget.analysed_layer = viewer.layers[0] + widget.plot_x_axis.setCurrentText("feature1") + widget.plot_y_axis.setCurrentText("feature2") + widget.analysed_layer.features["MANUAL_CLUSTER_ID"] = annotations + + # check that the features are found + features = get_layer_tabular_data(widget.analysed_layer) + assert "feature1" in features.columns + assert "feature2" in features.columns + + widget.run( + widget.analysed_layer.features, + plot_x_axis_name="feature1", + plot_y_axis_name="feature2", + plot_cluster_name="MANUAL_CLUSTER_ID", + force_redraw=True, + ) + +def test_plotter_on_labels3d_tracking(make_napari_viewer): + from napari_clusters_plotter._plotter import PlotterWidget + from napari_clusters_plotter._utilities import get_layer_tabular_data + + viewer = make_napari_viewer() + # Generate 3D tracking data + z_slices = 3 + n_timepoints = 2 + n_labels = get_labels_array().max() + data_3d_tracking = np.array([np.roll(np.stack([get_labels_array() for _ in range(z_slices)]), t, axis=1) for t in range(n_timepoints)]) + # Create some random features + label_column = np.arange(1, n_labels+1) + feature1 = np.random.normal(size=n_labels) + feature2 = np.random.normal(size=n_labels, loc=1) + annotations = 1 * (np.random.uniform(size=n_labels) > 0.5) + # Note how there is no frame column for tracking data, because we are analyzing features for the whole tracks + + viewer.add_labels(data_3d_tracking, properties={"label": label_column, "feature1": feature1, "feature2": feature2, "annotations": annotations}) + + widget = PlotterWidget(viewer) + viewer.window.add_dock_widget(widget) + + # Put the labels layer into the layer selection widget + widget.analysed_layer = viewer.layers[0] + widget.plot_x_axis.setCurrentText("feature1") + widget.plot_y_axis.setCurrentText("feature2") + widget.analysed_layer.features["MANUAL_CLUSTER_ID"] = annotations + + # check that the features are found + features = get_layer_tabular_data(widget.analysed_layer) + assert "feature1" in features.columns + assert "feature2" in features.columns + + widget.run( + widget.analysed_layer.features, + plot_x_axis_name="feature1", + plot_y_axis_name="feature2", + plot_cluster_name="MANUAL_CLUSTER_ID", + force_redraw=True, + ) + def test_plotter_utilities(): frame_ids = [0, 0, 1, 1, 2, 2, 3, 3] From da383f07c6824a126f9ea4854bc58e1e7f2f42ec Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 14:23:52 +0000 Subject: [PATCH 05/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../_tests/test_plotter.py | 138 ++++++++++++++---- 1 file changed, 109 insertions(+), 29 deletions(-) diff --git a/napari_clusters_plotter/_tests/test_plotter.py b/napari_clusters_plotter/_tests/test_plotter.py index 9d45800c..cd32f69d 100644 --- a/napari_clusters_plotter/_tests/test_plotter.py +++ b/napari_clusters_plotter/_tests/test_plotter.py @@ -78,6 +78,7 @@ def test_plotter_on_labels2d(make_napari_viewer): print("check") + def test_plotter_on_labels3d(make_napari_viewer): from napari_clusters_plotter._plotter import PlotterWidget from napari_clusters_plotter._utilities import get_layer_tabular_data @@ -88,12 +89,20 @@ def test_plotter_on_labels3d(make_napari_viewer): n_labels = get_labels_array().max() data_3d = np.stack([get_labels_array() for _ in range(z_slices)]) # Create some random features - label_column = np.arange(1, n_labels+1) + label_column = np.arange(1, n_labels + 1) feature1 = np.random.normal(size=n_labels) feature2 = np.random.normal(size=n_labels, loc=1) annotations = 1 * (np.random.uniform(size=n_labels) > 0.5) - viewer.add_labels(data_3d, properties={"label": label_column, "feature1": feature1, "feature2": feature2, "annotations": annotations}) + viewer.add_labels( + data_3d, + properties={ + "label": label_column, + "feature1": feature1, + "feature2": feature2, + "annotations": annotations, + }, + ) widget = PlotterWidget(viewer) viewer.window.add_dock_widget(widget) @@ -117,6 +126,7 @@ def test_plotter_on_labels3d(make_napari_viewer): force_redraw=True, ) + def test_plotter_on_labels2d_timelapse(make_napari_viewer): from napari_clusters_plotter._plotter import PlotterWidget from napari_clusters_plotter._utilities import get_layer_tabular_data @@ -125,16 +135,31 @@ def test_plotter_on_labels2d_timelapse(make_napari_viewer): # Generate 2D timelapse data n_timepoints = 2 n_labels = get_labels_array().max() - data_2d_timelapse = np.array([np.roll(get_labels_array(), t, axis=0) for t in range(n_timepoints)]) - data_2d_timelapse = np.expand_dims(data_2d_timelapse, axis=1) # add unidimensional z axis + data_2d_timelapse = np.array( + [np.roll(get_labels_array(), t, axis=0) for t in range(n_timepoints)] + ) + data_2d_timelapse = np.expand_dims( + data_2d_timelapse, axis=1 + ) # add unidimensional z axis # Create some random features - label_column = np.tile(np.arange(1, n_labels+1), n_timepoints) - feature1 = np.random.normal(size=n_labels*n_timepoints) - feature2 = np.random.normal(size=n_labels*n_timepoints, loc=1) - annotations = 1 * (np.random.uniform(size=n_labels*n_timepoints) > 0.5) - frame = np.arange(0, n_timepoints).repeat(n_labels) # add frame column for timelapsed data - - viewer.add_labels(data_2d_timelapse, properties={"label": label_column, "feature1": feature1, "feature2": feature2, "annotations": annotations, "frame": frame}) + label_column = np.tile(np.arange(1, n_labels + 1), n_timepoints) + feature1 = np.random.normal(size=n_labels * n_timepoints) + feature2 = np.random.normal(size=n_labels * n_timepoints, loc=1) + annotations = 1 * (np.random.uniform(size=n_labels * n_timepoints) > 0.5) + frame = np.arange(0, n_timepoints).repeat( + n_labels + ) # add frame column for timelapsed data + + viewer.add_labels( + data_2d_timelapse, + properties={ + "label": label_column, + "feature1": feature1, + "feature2": feature2, + "annotations": annotations, + "frame": frame, + }, + ) widget = PlotterWidget(viewer) viewer.window.add_dock_widget(widget) @@ -158,6 +183,7 @@ def test_plotter_on_labels2d_timelapse(make_napari_viewer): force_redraw=True, ) + def test_plotter_on_labels3d_timelapse(make_napari_viewer): from napari_clusters_plotter._plotter import PlotterWidget from napari_clusters_plotter._utilities import get_layer_tabular_data @@ -167,15 +193,31 @@ def test_plotter_on_labels3d_timelapse(make_napari_viewer): z_slices = 3 n_timepoints = 2 n_labels = get_labels_array().max() - data_3d_timelapse = np.array([np.roll(np.stack([get_labels_array() for _ in range(z_slices)]), t, axis=1) for t in range(n_timepoints)]) + data_3d_timelapse = np.array( + [ + np.roll(np.stack([get_labels_array() for _ in range(z_slices)]), t, axis=1) + for t in range(n_timepoints) + ] + ) # Create some random features - label_column = np.tile(np.arange(1, n_labels+1), n_timepoints) - feature1 = np.random.normal(size=n_labels*n_timepoints) - feature2 = np.random.normal(size=n_labels*n_timepoints, loc=1) - annotations = 1 * (np.random.uniform(size=n_labels*n_timepoints) > 0.5) - frame = np.arange(0, n_timepoints).repeat(n_labels) # add frame column for timelapsed data - - viewer.add_labels(data_3d_timelapse, properties={"label": label_column, "feature1": feature1, "feature2": feature2, "annotations": annotations, "frame": frame}) + label_column = np.tile(np.arange(1, n_labels + 1), n_timepoints) + feature1 = np.random.normal(size=n_labels * n_timepoints) + feature2 = np.random.normal(size=n_labels * n_timepoints, loc=1) + annotations = 1 * (np.random.uniform(size=n_labels * n_timepoints) > 0.5) + frame = np.arange(0, n_timepoints).repeat( + n_labels + ) # add frame column for timelapsed data + + viewer.add_labels( + data_3d_timelapse, + properties={ + "label": label_column, + "feature1": feature1, + "feature2": feature2, + "annotations": annotations, + "frame": frame, + }, + ) widget = PlotterWidget(viewer) viewer.window.add_dock_widget(widget) @@ -199,6 +241,7 @@ def test_plotter_on_labels3d_timelapse(make_napari_viewer): force_redraw=True, ) + def test_plotter_on_labels2d_tracking(make_napari_viewer): from napari_clusters_plotter._plotter import PlotterWidget from napari_clusters_plotter._utilities import get_layer_tabular_data @@ -207,16 +250,28 @@ def test_plotter_on_labels2d_tracking(make_napari_viewer): # Generate 2D tracking data n_timepoints = 2 n_labels = get_labels_array().max() - data_2d_tracking = np.array([np.roll(get_labels_array(), t, axis=0) for t in range(n_timepoints)]) - data_2d_tracking = np.expand_dims(data_2d_tracking, axis=1) # add unidimensional z axis + data_2d_tracking = np.array( + [np.roll(get_labels_array(), t, axis=0) for t in range(n_timepoints)] + ) + data_2d_tracking = np.expand_dims( + data_2d_tracking, axis=1 + ) # add unidimensional z axis # Create some random features - label_column = np.arange(1, n_labels+1) + label_column = np.arange(1, n_labels + 1) feature1 = np.random.normal(size=n_labels) feature2 = np.random.normal(size=n_labels, loc=1) annotations = 1 * (np.random.uniform(size=n_labels) > 0.5) # Note how there is no frame column for tracking data, because we are analyzing features for the whole tracks - viewer.add_labels(data_2d_tracking, properties={"label": label_column, "feature1": feature1, "feature2": feature2, "annotations": annotations}) + viewer.add_labels( + data_2d_tracking, + properties={ + "label": label_column, + "feature1": feature1, + "feature2": feature2, + "annotations": annotations, + }, + ) widget = PlotterWidget(viewer) viewer.window.add_dock_widget(widget) @@ -240,6 +295,7 @@ def test_plotter_on_labels2d_tracking(make_napari_viewer): force_redraw=True, ) + def test_plotter_on_labels3d_tracking(make_napari_viewer): from napari_clusters_plotter._plotter import PlotterWidget from napari_clusters_plotter._utilities import get_layer_tabular_data @@ -249,15 +305,28 @@ def test_plotter_on_labels3d_tracking(make_napari_viewer): z_slices = 3 n_timepoints = 2 n_labels = get_labels_array().max() - data_3d_tracking = np.array([np.roll(np.stack([get_labels_array() for _ in range(z_slices)]), t, axis=1) for t in range(n_timepoints)]) + data_3d_tracking = np.array( + [ + np.roll(np.stack([get_labels_array() for _ in range(z_slices)]), t, axis=1) + for t in range(n_timepoints) + ] + ) # Create some random features - label_column = np.arange(1, n_labels+1) + label_column = np.arange(1, n_labels + 1) feature1 = np.random.normal(size=n_labels) feature2 = np.random.normal(size=n_labels, loc=1) annotations = 1 * (np.random.uniform(size=n_labels) > 0.5) # Note how there is no frame column for tracking data, because we are analyzing features for the whole tracks - viewer.add_labels(data_3d_tracking, properties={"label": label_column, "feature1": feature1, "feature2": feature2, "annotations": annotations}) + viewer.add_labels( + data_3d_tracking, + properties={ + "label": label_column, + "feature1": feature1, + "feature2": feature2, + "annotations": annotations, + }, + ) widget = PlotterWidget(viewer) viewer.window.add_dock_widget(widget) @@ -449,7 +518,11 @@ def test_plotter_on_points_data4d(make_napari_viewer): feature2 = np.random.normal(size=n_points, loc=1) annotations = 1 * (np.random.uniform(size=100) > 0.5) - viewer.add_points(points, properties={"feature1": feature1, "feature2": feature2, 'frame': points[:, 0]}, size=0.1) + viewer.add_points( + points, + properties={"feature1": feature1, "feature2": feature2, "frame": points[:, 0]}, + size=0.1, + ) widget = PlotterWidget(viewer) viewer.window.add_dock_widget(widget) @@ -536,8 +609,15 @@ def test_plotter_on_surface_data4d(make_napari_viewer): surface_tuple = (vertices, faces) # need to add features later-on as napari currently doesn't support features for surfaces - layer = viewer.add_surface(surface_tuple, name='random_mesh') - layer.features = pd.DataFrame({'feature1': feature1, 'feature2': feature2, 'frame': vertices[:, 0], 'annotations': annotations}) + layer = viewer.add_surface(surface_tuple, name="random_mesh") + layer.features = pd.DataFrame( + { + "feature1": feature1, + "feature2": feature2, + "frame": vertices[:, 0], + "annotations": annotations, + } + ) widget = PlotterWidget(viewer) viewer.window.add_dock_widget(widget) From bcc089839c13e0f2928588851c4ed0fd8cc2cfa9 Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Tue, 23 Apr 2024 16:29:26 +0200 Subject: [PATCH 06/11] Update test_and_deploy.yml --- .github/workflows/test_and_deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_and_deploy.yml b/.github/workflows/test_and_deploy.yml index 1b14df0a..730b8039 100644 --- a/.github/workflows/test_and_deploy.yml +++ b/.github/workflows/test_and_deploy.yml @@ -29,7 +29,7 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} From 78e54c55b9e011c5cba6a55297356ef77618603a Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Tue, 23 Apr 2024 16:39:22 +0200 Subject: [PATCH 07/11] Update test_and_deploy.yml --- .github/workflows/test_and_deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_and_deploy.yml b/.github/workflows/test_and_deploy.yml index 730b8039..f97db0f3 100644 --- a/.github/workflows/test_and_deploy.yml +++ b/.github/workflows/test_and_deploy.yml @@ -22,7 +22,7 @@ jobs: runs-on: ${{ matrix.platform }} strategy: matrix: - platform: [ubuntu-latest, macos-latest] # windows-latest (disabled, see related issue) + platform: [ubuntu-latest, windows-latest] # macos-latest (disabled, see related issue) python-version: [3.8, 3.9] steps: From a8b1fe7d531f90221bc6aaabe376519316c938e2 Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Wed, 24 Apr 2024 08:39:18 +0200 Subject: [PATCH 08/11] Ensure 4D data under labels3d_timelapse Co-authored-by: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com> --- napari_clusters_plotter/_tests/test_plotter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/napari_clusters_plotter/_tests/test_plotter.py b/napari_clusters_plotter/_tests/test_plotter.py index cd32f69d..7c5e97f7 100644 --- a/napari_clusters_plotter/_tests/test_plotter.py +++ b/napari_clusters_plotter/_tests/test_plotter.py @@ -199,6 +199,7 @@ def test_plotter_on_labels3d_timelapse(make_napari_viewer): for t in range(n_timepoints) ] ) + assert len(data_3d_timelapse) == 4 # Create some random features label_column = np.tile(np.arange(1, n_labels + 1), n_timepoints) feature1 = np.random.normal(size=n_labels * n_timepoints) From d8cdaa9ba1af9bc791f0d8d0189f340ae1dd688b Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Wed, 24 Apr 2024 08:44:46 +0200 Subject: [PATCH 09/11] Ensure 4D data for 2D_timelapse (z must exist and be unidimensional for proper napari display) --- napari_clusters_plotter/_tests/test_plotter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/napari_clusters_plotter/_tests/test_plotter.py b/napari_clusters_plotter/_tests/test_plotter.py index 7c5e97f7..6b2a5bb6 100644 --- a/napari_clusters_plotter/_tests/test_plotter.py +++ b/napari_clusters_plotter/_tests/test_plotter.py @@ -141,6 +141,7 @@ def test_plotter_on_labels2d_timelapse(make_napari_viewer): data_2d_timelapse = np.expand_dims( data_2d_timelapse, axis=1 ) # add unidimensional z axis + assert len(data_2d_timelapse) == 4 # Create some random features label_column = np.tile(np.arange(1, n_labels + 1), n_timepoints) feature1 = np.random.normal(size=n_labels * n_timepoints) From 8c89d5508d533e1cda70812c75221b3855c87b2f Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Wed, 24 Apr 2024 08:46:06 +0200 Subject: [PATCH 10/11] shape should have length 4 --- napari_clusters_plotter/_tests/test_plotter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/napari_clusters_plotter/_tests/test_plotter.py b/napari_clusters_plotter/_tests/test_plotter.py index 6b2a5bb6..9c12edb4 100644 --- a/napari_clusters_plotter/_tests/test_plotter.py +++ b/napari_clusters_plotter/_tests/test_plotter.py @@ -141,7 +141,7 @@ def test_plotter_on_labels2d_timelapse(make_napari_viewer): data_2d_timelapse = np.expand_dims( data_2d_timelapse, axis=1 ) # add unidimensional z axis - assert len(data_2d_timelapse) == 4 + assert len(data_2d_timelapse.shape) == 4 # Create some random features label_column = np.tile(np.arange(1, n_labels + 1), n_timepoints) feature1 = np.random.normal(size=n_labels * n_timepoints) @@ -200,7 +200,7 @@ def test_plotter_on_labels3d_timelapse(make_napari_viewer): for t in range(n_timepoints) ] ) - assert len(data_3d_timelapse) == 4 + assert len(data_3d_timelapse.shape) == 4 # Create some random features label_column = np.tile(np.arange(1, n_labels + 1), n_timepoints) feature1 = np.random.normal(size=n_labels * n_timepoints) From a002d5f338ea321f0b07ebb59ac28273b36e7154 Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Wed, 24 Apr 2024 09:33:45 +0200 Subject: [PATCH 11/11] bump version --- napari_clusters_plotter/__init__.py | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/napari_clusters_plotter/__init__.py b/napari_clusters_plotter/__init__.py index 7ad46881..26a3977e 100644 --- a/napari_clusters_plotter/__init__.py +++ b/napari_clusters_plotter/__init__.py @@ -1,4 +1,4 @@ -__version__ = "0.7.3" +__version__ = "0.8.0" from ._dock_widget import ( diff --git a/setup.cfg b/setup.cfg index b09132bc..18085b90 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = napari-clusters-plotter -version = 0.7.3 +version = 0.8.0 author = Laura Zigutyte, Ryan Savill, Johannes Müller, Marcelo Zoccoler, Thorsten Wagner, Robert Haase author_email = zigutyte@gmail.com, robert.haase@tu-dresden.de