1- import os
2-
31import napari
42import napari .layers
53import numpy as np
119from .base_widget import BaseWidget
1210from .. import distance_measurements
1311
14- try :
15- from napari_skimage_regionprops import add_table
16- except ImportError :
17- add_table = None
18-
19-
20- def _save_distance_table (save_path , data ):
21- ext = os .path .splitext (save_path )[1 ]
22- if ext == "" : # No file extension given, By default we save to CSV.
23- file_path = f"{ save_path } .csv"
24- data .to_csv (file_path , index = False )
25- elif ext == ".csv" : # Extension was specified as csv
26- file_path = save_path
27- data .to_csv (file_path , index = False )
28- elif ext == ".xlsx" : # We also support excel.
29- file_path = save_path
30- data .to_excel (file_path , index = False )
31- else :
32- raise ValueError ("Invalid extension for table: {ext}. We support .csv or .xlsx." )
33- return file_path
34-
3512
3613class DistanceMeasureWidget (BaseWidget ):
3714 def __init__ (self ):
@@ -68,47 +45,33 @@ def __init__(self):
6845 def _to_table_data (self , distances , seg_ids , endpoints1 = None , endpoints2 = None ):
6946 assert len (distances ) == len (seg_ids ), f"{ distances .shape } , { seg_ids .shape } "
7047 if seg_ids .ndim == 2 :
71- table_data = {"label1 " : seg_ids [:, 0 ], "label2 " : seg_ids [:, 1 ], "distance" : distances }
48+ table_data = {"label_id1 " : seg_ids [:, 0 ], "label_id2 " : seg_ids [:, 1 ], "distance" : distances }
7249 else :
73- table_data = {"label " : seg_ids , "distance" : distances }
50+ table_data = {"label_id " : seg_ids , "distance" : distances }
7451 if endpoints1 is not None :
7552 axis_names = "zyx" if endpoints1 .shape [1 ] == 3 else "yx"
7653 table_data .update ({f"begin-{ ax } " : endpoints1 [:, i ] for i , ax in enumerate (axis_names )})
7754 table_data .update ({f"end-{ ax } " : endpoints2 [:, i ] for i , ax in enumerate (axis_names )})
7855 return pd .DataFrame (table_data )
7956
80- def _add_lines_and_table (self , lines , properties , table_data , name ):
57+ def _add_lines_and_table (self , lines , table_data , name ):
8158 line_layer = self .viewer .add_shapes (
8259 lines ,
8360 name = name ,
8461 shape_type = "line" ,
8562 edge_width = 2 ,
8663 edge_color = "red" ,
8764 blending = "additive" ,
88- properties = properties ,
8965 )
90- if add_table is not None :
91- add_table (line_layer , self .viewer )
92-
93- if self .save_path .text () != "" :
94- file_path = _save_distance_table (self .save_path .text (), table_data )
95-
96- if self .save_path .text () != "" :
97- show_info (f"Added distance lines and saved file to { file_path } ." )
98- else :
99- show_info ("Added distance lines." )
66+ self ._add_properties_and_table (line_layer , table_data , self .save_path .text ())
10067
10168 def on_measure_seg_to_object (self ):
10269 segmentation = self ._get_layer_selector_data (self .image_selector_name1 )
10370 object_data = self ._get_layer_selector_data (self .image_selector_name2 )
104- # get metadata from layer if available
71+
72+ # Get the resolution / voxel size.
10573 metadata = self ._get_layer_selector_data (self .image_selector_name1 , return_metadata = True )
106- resolution = metadata .get ("voxel_size" , None )
107- if resolution is not None :
108- resolution = [v for v in resolution .values ()]
109- # if user input is present override metadata
110- if self .voxel_size_param .value () != 0.0 : # changed from default
111- resolution = segmentation .ndim * [self .voxel_size_param .value ()]
74+ resolution = self ._handle_resolution (metadata , self .voxel_size_param , segmentation .ndim )
11275
11376 (distances ,
11477 endpoints1 ,
@@ -117,28 +80,23 @@ def on_measure_seg_to_object(self):
11780 segmentation = segmentation , segmented_object = object_data , distance_type = "boundary" ,
11881 resolution = resolution
11982 )
120- lines , properties = distance_measurements .create_object_distance_lines (
83+ lines , _ = distance_measurements .create_object_distance_lines (
12184 distances = distances ,
12285 endpoints1 = endpoints1 ,
12386 endpoints2 = endpoints2 ,
12487 seg_ids = seg_ids ,
12588 )
12689 table_data = self ._to_table_data (distances , seg_ids , endpoints1 , endpoints2 )
127- self ._add_lines_and_table (lines , properties , table_data , name = "distances" )
90+ self ._add_lines_and_table (lines , table_data , name = "distances" )
12891
12992 def on_measure_pairwise (self ):
13093 segmentation = self ._get_layer_selector_data (self .image_selector_name1 )
13194 if segmentation is None :
13295 show_info ("Please choose a segmentation." )
13396 return
134- # get metadata from layer if available
97+
13598 metadata = self ._get_layer_selector_data (self .image_selector_name1 , return_metadata = True )
136- resolution = metadata .get ("voxel_size" , None )
137- if resolution is not None :
138- resolution = [v for v in resolution .values ()]
139- # if user input is present override metadata
140- if self .voxel_size_param .value () != 0.0 : # changed from default
141- resolution = segmentation .ndim * [self .voxel_size_param .value ()]
99+ resolution = self ._handle_resolution (metadata , self .voxel_size_param , segmentation .ndim )
142100
143101 (distances ,
144102 endpoints1 ,
@@ -153,7 +111,7 @@ def on_measure_pairwise(self):
153111 distances = properties ["distance" ],
154112 seg_ids = np .concatenate ([properties ["id_a" ][:, None ], properties ["id_b" ][:, None ]], axis = 1 )
155113 )
156- self ._add_lines_and_table (lines , properties , table_data , name = "pairwise-distances" )
114+ self ._add_lines_and_table (lines , table_data , name = "pairwise-distances" )
157115
158116 def _create_settings_widget (self ):
159117 setting_values = QWidget ()
0 commit comments