From 18d2fb833a53720df666b8b8c2fa975202851c7e Mon Sep 17 00:00:00 2001 From: savill <65285466+Cryaaa@users.noreply.github.com> Date: Wed, 27 Mar 2024 09:28:13 +0100 Subject: [PATCH 01/10] Update _table.py --- napari_skimage_regionprops/_table.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/napari_skimage_regionprops/_table.py b/napari_skimage_regionprops/_table.py index ca1011b..8fd9966 100644 --- a/napari_skimage_regionprops/_table.py +++ b/napari_skimage_regionprops/_table.py @@ -31,6 +31,8 @@ def __init__(self, layer: "napari.layers.Layer", viewer: "napari.Viewer" = None) self._view.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers) if hasattr(layer, "properties"): self.set_content(layer.properties) + elif hasattr(layer, "features"): + self.set_content(layer.features.to_dict(orient="list")) else: self.set_content({}) From 0bc937b98444c07a116648066fde1314bbe0095d Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Wed, 24 Apr 2024 11:26:38 +0200 Subject: [PATCH 02/10] Initialize Surface layer properties and features if not already set --- napari_skimage_regionprops/_table.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/napari_skimage_regionprops/_table.py b/napari_skimage_regionprops/_table.py index 8fd9966..1c62ead 100644 --- a/napari_skimage_regionprops/_table.py +++ b/napari_skimage_regionprops/_table.py @@ -29,6 +29,13 @@ def __init__(self, layer: "napari.layers.Layer", viewer: "napari.Viewer" = None) self._view = QTableWidget() self._view.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers) + # Add 'properties' and 'features' attributes if layer is Surface + if isinstance(layer, napari.layers.Surface): + # Check if features and properties are already defined + if not hasattr(layer, "features"): + layer.features = {} + if not hasattr(layer, "properties"): + layer.properties = {} if hasattr(layer, "properties"): self.set_content(layer.properties) elif hasattr(layer, "features"): From 3dffb00e8f82ab207098ada63821e787b41b94af Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Wed, 24 Apr 2024 11:29:07 +0200 Subject: [PATCH 03/10] Allow load_csv to load to any layer type, initialize surface features and properties, and match table shape in properties of points layer to number of points --- napari_skimage_regionprops/_load_csv.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/napari_skimage_regionprops/_load_csv.py b/napari_skimage_regionprops/_load_csv.py index 40c90de..178c568 100644 --- a/napari_skimage_regionprops/_load_csv.py +++ b/napari_skimage_regionprops/_load_csv.py @@ -9,7 +9,7 @@ @register_function(menu="Measurement > Load from CSV (nsr)") -def load_csv(csv_filename:"magicgui.types.PathLike", labels_layer: "napari.layers.Labels", show_table: bool = True, viewer: "napari.Viewer" = None): +def load_csv(csv_filename:"magicgui.types.PathLike", labels_layer: "napari.layers.Layer", show_table: bool = True, viewer: "napari.Viewer" = None): """Save contents of a CSV file into a given layer's properties""" import pandas as pd # load region properties from csv file @@ -24,9 +24,18 @@ def load_csv(csv_filename:"magicgui.types.PathLike", labels_layer: "napari.layer {"label": np.array(range(1, (len(edited_reg_props) + 1)))} ) edited_reg_props = pd.concat([label_column, edited_reg_props], axis=1) - + # Add 'properties' and 'features' attributes if layer is Surface + if isinstance(labels_layer, napari.layers.Surface): + # Check if features and properties are already defined + if not hasattr(labels_layer, "features"): + labels_layer.features = {} + if not hasattr(labels_layer, "properties"): + labels_layer.properties = {} + elif isinstance(labels_layer, napari.layers.Points): + # Table shape must match number of points, so truncate if necessary + edited_reg_props = edited_reg_props.iloc[:labels_layer.data.shape[0],:] if hasattr(labels_layer, "properties"): - labels_layer.properties = edited_reg_props + labels_layer.properties = edited_reg_props.to_dict(orient="list") if hasattr(labels_layer, "features"): labels_layer.features = edited_reg_props From 75deda73d3a06018572ed04c3cfcfc7ce48bd863 Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Wed, 24 Apr 2024 12:03:12 +0200 Subject: [PATCH 04/10] Match points layer properties shape to data shape --- napari_skimage_regionprops/_load_csv.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/napari_skimage_regionprops/_load_csv.py b/napari_skimage_regionprops/_load_csv.py index 178c568..e1d64be 100644 --- a/napari_skimage_regionprops/_load_csv.py +++ b/napari_skimage_regionprops/_load_csv.py @@ -1,5 +1,6 @@ import numpy as np from napari_tools_menu import register_function +from napari.utils.notifications import show_warning try: import napari @@ -32,8 +33,15 @@ def load_csv(csv_filename:"magicgui.types.PathLike", labels_layer: "napari.layer if not hasattr(labels_layer, "properties"): labels_layer.properties = {} elif isinstance(labels_layer, napari.layers.Points): - # Table shape must match number of points, so truncate if necessary - edited_reg_props = edited_reg_props.iloc[:labels_layer.data.shape[0],:] + # Table shape must match number of points + if edited_reg_props.shape[0] < labels_layer.data.shape[0]: + # fill in missing rows with NaNs + show_warning("Number of rows in CSV file is less than number of points in the layer. Filling in missing rows with NaNs.") + edited_reg_props = pd.concat([edited_reg_props, pd.DataFrame(np.nan, index=range(labels_layer.data.shape[0] - edited_reg_props.shape[0]), columns=edited_reg_props.columns)]).reset_index(drop=True) + elif edited_reg_props.shape[0] > labels_layer.data.shape[0]: + # truncate if necessary + show_warning("Number of rows in CSV file is greater than number of points in the layer. Truncating to match number of points.") + edited_reg_props = edited_reg_props.iloc[:labels_layer.data.shape[0],:] if hasattr(labels_layer, "properties"): labels_layer.properties = edited_reg_props.to_dict(orient="list") if hasattr(labels_layer, "features"): From 22a788c19c155de635f6a7f8d0f3b16052af7aa2 Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Wed, 24 Apr 2024 12:10:12 +0200 Subject: [PATCH 05/10] add tests for loading csv to surface and points layers --- .../_tests/test_function.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/napari_skimage_regionprops/_tests/test_function.py b/napari_skimage_regionprops/_tests/test_function.py index 3dcc9f3..45eb186 100644 --- a/napari_skimage_regionprops/_tests/test_function.py +++ b/napari_skimage_regionprops/_tests/test_function.py @@ -1,4 +1,40 @@ # from napari_skimage_regionprops import threshold, image_arithmetic +def generate_sphere_mesh(radius, segments): + """ + Generate vertices and faces for a sphere mesh. + + Parameters: + radius (float): Radius of the sphere. + segments (int): Number of segments used to generate the sphere, higher means finer mesh. + + Returns: + tuple: vertices (N, 3 array), faces (M, 3 array) + """ + import numpy as np + theta = np.linspace(0, np.pi, segments) + phi = np.linspace(0, 2 * np.pi, segments) + theta, phi = np.meshgrid(theta, phi) + + x = radius * np.sin(theta) * np.cos(phi) + y = radius * np.sin(theta) * np.sin(phi) + z = radius * np.cos(theta) + + vertices = np.column_stack((x.ravel(), y.ravel(), z.ravel())) + + # Generate faces (indices of vertices that make up each triangle) + faces = [] + for i in range(len(theta) - 1): + for j in range(len(phi) - 1): + v0 = i * len(phi) + j + v1 = v0 + 1 + v2 = v0 + len(phi) + v3 = v2 + 1 + faces.append([v0, v1, v2]) + faces.append([v1, v3, v2]) + + faces = np.array(faces) + + return vertices, faces # add your tests here... def test_regionprops(make_napari_viewer): @@ -90,6 +126,17 @@ def test_regionprops(make_napari_viewer): load_csv("test.csv", labels_layer) load_csv("test.csv", labels_layer, viewer) + points_layer = viewer.add_points(np.array([[2, 1], [2, 5], [5, 3], [6, 6]])) + vertices, faces = generate_sphere_mesh(1, 50) + surface_layer = viewer.add_surface((vertices, faces)) + + # test loading csv to points + load_csv("test.csv", points_layer) + load_csv("test.csv", points_layer, viewer) + + # test loading csv to surface + load_csv("test.csv", surface_layer) + load_csv("test.csv", surface_layer, viewer) # empty table table_widget.set_content(None) From 7ccd2291977cb710bbe5711456bfe72644929f91 Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Wed, 24 Apr 2024 12:12:55 +0200 Subject: [PATCH 06/10] mac tests disabled for the moment (related issue: actions/setup-python#808) --- .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 fe30132..5ee52ec 100644 --- a/.github/workflows/test_and_deploy.yml +++ b/.github/workflows/test_and_deploy.yml @@ -19,7 +19,7 @@ jobs: runs-on: ${{ matrix.platform }} strategy: matrix: - platform: [ubuntu-latest, windows-latest, macos-latest] + platform: [ubuntu-latest, windows-latest] #, macos-latest] python-version: ['3.8', '3.9', '3.10'] steps: From dd48037209158e9a32fe379049cc8095b5c719fb Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Wed, 24 Apr 2024 14:20:30 +0200 Subject: [PATCH 07/10] fixing ubuntu version for now (related to this: https://github.com/orgs/community/discussions/120966) --- .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 5ee52ec..15ba6cb 100644 --- a/.github/workflows/test_and_deploy.yml +++ b/.github/workflows/test_and_deploy.yml @@ -19,7 +19,7 @@ jobs: runs-on: ${{ matrix.platform }} strategy: matrix: - platform: [ubuntu-latest, windows-latest] #, macos-latest] + platform: [ubuntu-20.04, windows-latest] #, macos-latest] python-version: ['3.8', '3.9', '3.10'] steps: From 89b2b877d60f42c205a0a175b8ef6f62c6f7c6d3 Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Thu, 25 Apr 2024 10:03:48 +0200 Subject: [PATCH 08/10] mirror properties and features attributes if they are set before --- napari_skimage_regionprops/_table.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/napari_skimage_regionprops/_table.py b/napari_skimage_regionprops/_table.py index 1c62ead..6ca93b8 100644 --- a/napari_skimage_regionprops/_table.py +++ b/napari_skimage_regionprops/_table.py @@ -34,12 +34,16 @@ def __init__(self, layer: "napari.layers.Layer", viewer: "napari.Viewer" = None) # Check if features and properties are already defined if not hasattr(layer, "features"): layer.features = {} + else: + # Mirror properties to features + layer.properties = layer.features.to_dict(orient="list") if not hasattr(layer, "properties"): layer.properties = {} + else: + # Mirror features to properties + layer.features = pd.DataFrame(layer.properties) if hasattr(layer, "properties"): self.set_content(layer.properties) - elif hasattr(layer, "features"): - self.set_content(layer.features.to_dict(orient="list")) else: self.set_content({}) From 08f41ab9ef4887481516f75a61c1ac801d9c9e42 Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Thu, 25 Apr 2024 10:08:31 +0200 Subject: [PATCH 09/10] fix tests for macos --- .github/workflows/test_and_deploy.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test_and_deploy.yml b/.github/workflows/test_and_deploy.yml index 15ba6cb..0213364 100644 --- a/.github/workflows/test_and_deploy.yml +++ b/.github/workflows/test_and_deploy.yml @@ -19,8 +19,13 @@ jobs: runs-on: ${{ matrix.platform }} strategy: matrix: - platform: [ubuntu-20.04, windows-latest] #, macos-latest] + platform: [ubuntu-20.04, windows-latest, macos-13, macos-14] python-version: ['3.8', '3.9', '3.10'] + exclude: + - python-version: "3.8" + platform: macos-14 + - python-version: "3.9" + platform: macos-14 steps: - uses: actions/checkout@v3 From e51aeaf1b676af30c573bc9c527536bddadc8071 Mon Sep 17 00:00:00 2001 From: Marcelo Zoccoler Date: Thu, 25 Apr 2024 10:11:18 +0200 Subject: [PATCH 10/10] unpin ubuntu version as issue was fixed --- .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 0213364..5095070 100644 --- a/.github/workflows/test_and_deploy.yml +++ b/.github/workflows/test_and_deploy.yml @@ -19,7 +19,7 @@ jobs: runs-on: ${{ matrix.platform }} strategy: matrix: - platform: [ubuntu-20.04, windows-latest, macos-13, macos-14] + platform: [ubuntu-latest, windows-latest, macos-13, macos-14] python-version: ['3.8', '3.9', '3.10'] exclude: - python-version: "3.8"