synapse_net.tools.vesicle_pool_widget
1from typing import Dict 2 3import napari 4import napari.layers 5import napari.viewer 6import numpy as np 7import pandas as pd 8 9from napari.utils.notifications import show_info 10from qtpy.QtWidgets import QWidget, QVBoxLayout, QPushButton 11 12from .base_widget import BaseWidget 13 14# This will fail if we have more than 8 pools. 15COLORMAP = ["red", "blue", "yellow", "cyan", "purple", "magenta", "orange", "green"] 16 17 18class VesiclePoolWidget(BaseWidget): 19 def __init__(self): 20 super().__init__() 21 22 self.viewer = napari.current_viewer() 23 layout = QVBoxLayout() 24 25 # Create the selectors for the layers: 26 # 1. Selector for the labels layer with vesicles. 27 self.vesicle_selector_name = "Vesicle Segmentation" 28 self.vesicle_selector_widget = self._create_layer_selector(self.vesicle_selector_name, layer_type="Labels") 29 # 2. Selector for a distance layer. 30 self.dist_selector_name1 = "Distances to Structure" 31 self.dist_selector_widget1 = self._create_layer_selector(self.dist_selector_name1, layer_type="Shapes") 32 # 3. Selector for a second distance layer (optional). 33 self.dist_selector_name2 = "Distances to Structure 2" 34 self.dist_selector_widget2 = self._create_layer_selector(self.dist_selector_name2, layer_type="Shapes") 35 36 # Add the selector widgets to the layout. 37 layout.addWidget(self.vesicle_selector_widget) 38 layout.addWidget(self.dist_selector_widget1) 39 layout.addWidget(self.dist_selector_widget2) 40 41 # Create the UI elements for defining the vesicle pools: 42 # The name of the output name, the name of the vesicle pool, and the criterion for the pool. 43 self.pool_layer_name_param, pool_layer_name_layout = self._add_string_param(name="Layer Name", value="") 44 self.pool_name_param, pool_name_layout = self._add_string_param(name="Vesicle Pool", value="") 45 self.query_param, query_layout = self._add_string_param( 46 name="Criterion", value="", 47 tooltip="Enter a comma separated criterion (e.g., 'radius > 15, distance > 250') " 48 "Possible filters: radius, distance, area, intensity_max, intensity_mean, intensity_min, intensity_std" 49 ) 50 layout.addLayout(pool_layer_name_layout) 51 layout.addLayout(pool_name_layout) 52 layout.addLayout(query_layout) 53 54 # Create the UI elements for advanced settings and the run button. 55 self.settings = self._create_settings_widget() 56 self.measure_button = QPushButton("Create Vesicle Pool") 57 self.measure_button.clicked.connect(self.on_pool_vesicles) 58 layout.addWidget(self.settings) 59 layout.addWidget(self.measure_button) 60 61 self.setLayout(layout) 62 63 # The colormap for displaying the vesicle pools. 64 self.pool_colors = {} 65 66 def on_pool_vesicles(self): 67 segmentation = self._get_layer_selector_data(self.vesicle_selector_name) 68 morphology = self._get_layer_selector_layer(self.vesicle_selector_name).properties 69 if not morphology: 70 morphology = None 71 72 distance_layer = self._get_layer_selector_layer(self.dist_selector_name1) 73 distances = None if distance_layer is None else distance_layer.properties 74 distance_layer2 = self._get_layer_selector_layer(self.dist_selector_name2) 75 # Check if the second distance is the same as the first. 76 if distance_layer2.name == distance_layer.name: 77 distance_layer2 = None 78 distances2 = None if distance_layer2 is None else distance_layer2.properties 79 80 if segmentation is None: 81 show_info("INFO: Please choose a segmentation.") 82 return 83 if self.query_param.text() == "": 84 show_info("INFO: Please enter a query string.") 85 return 86 query = self.query_param.text() 87 88 if self.pool_layer_name_param.text() == "": 89 show_info("INFO: Please enter a name for the pool layer.") 90 return 91 pool_layer_name = self.pool_layer_name_param.text() 92 if self.pool_name_param.text() == "": 93 show_info("INFO: Please enter a name for the vesicle pool.") 94 return 95 pool_name = self.pool_name_param.text() 96 97 pool_color = self.pool_color_param.text() 98 self._compute_vesicle_pool( 99 segmentation, distances, morphology, pool_layer_name, pool_name, query, pool_color, distances2 100 ) 101 102 def _update_pool_colors(self, pool_name, pool_color): 103 if pool_color == "": 104 next_color_id = len(self.pool_colors) 105 next_color = COLORMAP[next_color_id] 106 else: 107 # We could check here that this is a valid color. 108 next_color = pool_color 109 self.pool_colors[pool_name] = next_color 110 111 def _add_colors(self, pool_properties, vesicle_colors): 112 colors = np.array([vesicle_colors[label_id] for label_id in pool_properties.label.values]) 113 pool_properties["color"] = colors 114 return pool_properties 115 116 def _compute_vesicle_pool( 117 self, 118 segmentation: np.ndarray, 119 distances: Dict, 120 morphology: Dict, 121 pool_layer_name: str, 122 pool_name: str, 123 query: str, 124 pool_color: str, 125 distances2: Dict = None 126 ): 127 """Compute a vesicle pool based on the provided query parameters. 128 129 Args: 130 segmentation: Segmentation data (e.g., labeled regions). 131 distances: Properties from the distances layer. 132 morphology: Properties from the morphology layer. 133 pool_layer_name: Name for the new layer to be created. 134 pool_name: Name for the pooled group to be assigned. 135 query: Query parameters. 136 pool_color: Optional color for the vesicle pool. 137 distances2: Properties from the second distances layer (optional). 138 """ 139 # Check which of the properties are present and construct the combined properties based on this. 140 if distances is None and morphology is None: # No properties were given -> we can't do anything. 141 show_info("ERROR: Neither distances nor vesicle morphology were found.") 142 return 143 elif distances is None and morphology is not None: # Only morphology props were found. 144 merged_df = pd.DataFrame(morphology).drop(columns=["index"], errors="ignore") 145 elif distances is not None and morphology is None: # Only distances were found. 146 merged_df = pd.DataFrame(distances).drop(columns=["index"], errors="ignore") 147 else: # Both were found. 148 distance_ids = distances.get("label", []) 149 morphology_ids = morphology.get("label", []) 150 151 # Ensure that IDs are identical. 152 if set(distance_ids) != set(morphology_ids): 153 show_info("ERROR: The IDs in distances and morphology are not identical.") 154 return 155 156 # Create a merged dataframe from the dataframes which are relevant for the criterion. 157 distances = pd.DataFrame(distances).drop(columns=["index"]) 158 morphology = pd.DataFrame(morphology).drop(columns=["index"]) 159 merged_df = morphology.merge(distances, left_on="label", right_on="label", suffixes=("_morph", "_dist")) 160 # Add distances2 if present. 161 if distances2 is not None: 162 distance_ids = distances2.get("label", []) 163 if set(distance_ids) != set(merged_df.label): 164 show_info("ERROR: The IDs in distances2 and morphology are not identical.") 165 return 166 distances2 = pd.DataFrame(distances2).drop(columns=["index"]) 167 merged_df = merged_df.merge(distances2, left_on="label", right_on="label", suffixes=("", "2")) 168 # Assign the vesicles to the current pool by filtering the mergeddataframe based on the query. 169 filtered_df = self._parse_query(query, merged_df) 170 if len(filtered_df) == 0: 171 show_info("No vesicles were found matching the condition.") 172 return 173 pool_vesicle_ids = filtered_df.label.values.tolist() 174 vesicles_in_pool = len(pool_vesicle_ids) 175 176 # Check if this layer was already created in a previous pool assignment. 177 if pool_layer_name in self.viewer.layers: 178 # If yes then load the previous pool assignments and merge them with the new pool assignments 179 pool_layer = self.viewer.layers[pool_layer_name] 180 pool_properties = pd.DataFrame.from_dict(pool_layer.properties) 181 182 pool_names = pd.unique(pool_properties.pool) 183 if pool_name in pool_names: 184 show_info(f"Updating pool '{pool_name}' with {vesicles_in_pool} vesicles.") 185 # This pool has already been assigned and we changed the criterion. 186 # Its old assignment has to be over-written, remove the rows for this pool. 187 pool_properties = pool_properties[pool_properties.pool != pool_name] 188 else: 189 show_info(f"Creating pool '{pool_name}' with {vesicles_in_pool} vesicles.") 190 191 # Combine the vesicle ids corresponding to the previous assignment with the 192 # assignment for the new / current pool. 193 old_pool_ids = pool_properties.label.values.tolist() 194 195 # Overwrite the intersection of the two pool assignments with the new pool. 196 pool_intersections = np.intersect1d(pool_vesicle_ids, old_pool_ids) 197 old_pool_ids = [item for item in old_pool_ids if item not in pool_intersections] 198 pool_properties = pool_properties[~pool_properties["label"].isin(pool_intersections)] 199 200 pool_assignments = sorted(pool_vesicle_ids + old_pool_ids) 201 202 # Get a map for each vesicle id to its pool. 203 id_to_pool_name = {ves_id: pool_name for ves_id in pool_vesicle_ids} 204 id_to_pool_name.update({k: v for k, v in zip(old_pool_ids, pool_properties.pool.values)}) 205 206 # Get the pool values. 207 # This is the list of pool names, corresponding to the selected ids in pool_assignments. 208 pool_values = [id_to_pool_name[ves_id] for ves_id in pool_assignments] 209 210 else: 211 show_info(f"Creating pool '{pool_name}' with {vesicles_in_pool} vesicles.") 212 # Otherwise, this is the first pool assignment. 213 pool_assignments = pool_vesicle_ids 214 pool_values = [pool_name] * len(pool_assignments) 215 216 # Create the filtered segmentation. 217 vesicle_pools = segmentation.copy() 218 vesicle_pools[~np.isin(vesicle_pools, pool_assignments)] = 0 219 220 # Create the pool properties. 221 pool_properties = merged_df[merged_df.label.isin(pool_assignments)] 222 # Remove columns that are not relevant for measurements. 223 keep_columns = [ 224 col for col in pool_properties.columns 225 if col not in ("x", "y", "z", "begin-x", "begin-y", "begin-z", "end-x", "end-y", "end-z") 226 ] 227 pool_properties = pool_properties[keep_columns] 228 # Add a colun for the pool. 229 pool_properties.insert(1, "pool", pool_values) 230 231 # Update the colormap to display the pools. 232 self._update_pool_colors(pool_name, pool_color) 233 234 # Assign the vesicle ids to their pool color. 235 vesicle_colors = { 236 label_id: self.pool_colors[pname] for label_id, pname in zip( 237 pool_properties.label.values, pool_properties.pool.values 238 ) 239 } 240 vesicle_colors[None] = "gray" 241 242 # Add or replace the pool layer and properties. 243 if pool_layer_name in self.viewer.layers: 244 pool_layer = self.viewer.layers[pool_layer_name] 245 pool_layer.data = vesicle_pools 246 pool_layer.colormap = vesicle_colors 247 else: 248 pool_layer = self.viewer.add_labels(vesicle_pools, name=pool_layer_name, colormap=vesicle_colors) 249 250 pool_properties = self._add_colors(pool_properties, vesicle_colors) 251 self._add_properties_and_table(pool_layer, pool_properties, save_path=self.save_path.text()) 252 pool_layer.refresh() 253 254 def _parse_query(self, query: str, data: pd.DataFrame) -> pd.DataFrame: 255 """Parse and apply a query string to filter data. 256 257 Args: 258 query: Comma-separated query string (e.g., "radius > 15, distance > 250"). 259 data: DataFrame containing the data to filter. 260 261 Returns: 262 Filtered DataFrame. 263 """ 264 filters = query.split(",") # Split the query into individual conditions 265 filters = [f.strip() for f in filters] # Remove extra spaces 266 for condition in filters: 267 try: 268 # Apply each condition to filter the DataFrame 269 data = data.query(condition) 270 except Exception as e: 271 print(f"Failed to apply condition '{condition}': {e}") 272 continue 273 return data 274 275 def _create_settings_widget(self): 276 setting_values = QWidget() 277 setting_values.setLayout(QVBoxLayout()) 278 279 self.save_path, layout = self._add_path_param(name="Save Table", select_type="file", value="") 280 setting_values.layout().addLayout(layout) 281 282 self.pool_color_param, layout = self._add_string_param(name="Pool Color", value="") 283 setting_values.layout().addLayout(layout) 284 285 settings = self._make_collapsible(widget=setting_values, title="Advanced Settings") 286 return settings
COLORMAP =
['red', 'blue', 'yellow', 'cyan', 'purple', 'magenta', 'orange', 'green']
19class VesiclePoolWidget(BaseWidget): 20 def __init__(self): 21 super().__init__() 22 23 self.viewer = napari.current_viewer() 24 layout = QVBoxLayout() 25 26 # Create the selectors for the layers: 27 # 1. Selector for the labels layer with vesicles. 28 self.vesicle_selector_name = "Vesicle Segmentation" 29 self.vesicle_selector_widget = self._create_layer_selector(self.vesicle_selector_name, layer_type="Labels") 30 # 2. Selector for a distance layer. 31 self.dist_selector_name1 = "Distances to Structure" 32 self.dist_selector_widget1 = self._create_layer_selector(self.dist_selector_name1, layer_type="Shapes") 33 # 3. Selector for a second distance layer (optional). 34 self.dist_selector_name2 = "Distances to Structure 2" 35 self.dist_selector_widget2 = self._create_layer_selector(self.dist_selector_name2, layer_type="Shapes") 36 37 # Add the selector widgets to the layout. 38 layout.addWidget(self.vesicle_selector_widget) 39 layout.addWidget(self.dist_selector_widget1) 40 layout.addWidget(self.dist_selector_widget2) 41 42 # Create the UI elements for defining the vesicle pools: 43 # The name of the output name, the name of the vesicle pool, and the criterion for the pool. 44 self.pool_layer_name_param, pool_layer_name_layout = self._add_string_param(name="Layer Name", value="") 45 self.pool_name_param, pool_name_layout = self._add_string_param(name="Vesicle Pool", value="") 46 self.query_param, query_layout = self._add_string_param( 47 name="Criterion", value="", 48 tooltip="Enter a comma separated criterion (e.g., 'radius > 15, distance > 250') " 49 "Possible filters: radius, distance, area, intensity_max, intensity_mean, intensity_min, intensity_std" 50 ) 51 layout.addLayout(pool_layer_name_layout) 52 layout.addLayout(pool_name_layout) 53 layout.addLayout(query_layout) 54 55 # Create the UI elements for advanced settings and the run button. 56 self.settings = self._create_settings_widget() 57 self.measure_button = QPushButton("Create Vesicle Pool") 58 self.measure_button.clicked.connect(self.on_pool_vesicles) 59 layout.addWidget(self.settings) 60 layout.addWidget(self.measure_button) 61 62 self.setLayout(layout) 63 64 # The colormap for displaying the vesicle pools. 65 self.pool_colors = {} 66 67 def on_pool_vesicles(self): 68 segmentation = self._get_layer_selector_data(self.vesicle_selector_name) 69 morphology = self._get_layer_selector_layer(self.vesicle_selector_name).properties 70 if not morphology: 71 morphology = None 72 73 distance_layer = self._get_layer_selector_layer(self.dist_selector_name1) 74 distances = None if distance_layer is None else distance_layer.properties 75 distance_layer2 = self._get_layer_selector_layer(self.dist_selector_name2) 76 # Check if the second distance is the same as the first. 77 if distance_layer2.name == distance_layer.name: 78 distance_layer2 = None 79 distances2 = None if distance_layer2 is None else distance_layer2.properties 80 81 if segmentation is None: 82 show_info("INFO: Please choose a segmentation.") 83 return 84 if self.query_param.text() == "": 85 show_info("INFO: Please enter a query string.") 86 return 87 query = self.query_param.text() 88 89 if self.pool_layer_name_param.text() == "": 90 show_info("INFO: Please enter a name for the pool layer.") 91 return 92 pool_layer_name = self.pool_layer_name_param.text() 93 if self.pool_name_param.text() == "": 94 show_info("INFO: Please enter a name for the vesicle pool.") 95 return 96 pool_name = self.pool_name_param.text() 97 98 pool_color = self.pool_color_param.text() 99 self._compute_vesicle_pool( 100 segmentation, distances, morphology, pool_layer_name, pool_name, query, pool_color, distances2 101 ) 102 103 def _update_pool_colors(self, pool_name, pool_color): 104 if pool_color == "": 105 next_color_id = len(self.pool_colors) 106 next_color = COLORMAP[next_color_id] 107 else: 108 # We could check here that this is a valid color. 109 next_color = pool_color 110 self.pool_colors[pool_name] = next_color 111 112 def _add_colors(self, pool_properties, vesicle_colors): 113 colors = np.array([vesicle_colors[label_id] for label_id in pool_properties.label.values]) 114 pool_properties["color"] = colors 115 return pool_properties 116 117 def _compute_vesicle_pool( 118 self, 119 segmentation: np.ndarray, 120 distances: Dict, 121 morphology: Dict, 122 pool_layer_name: str, 123 pool_name: str, 124 query: str, 125 pool_color: str, 126 distances2: Dict = None 127 ): 128 """Compute a vesicle pool based on the provided query parameters. 129 130 Args: 131 segmentation: Segmentation data (e.g., labeled regions). 132 distances: Properties from the distances layer. 133 morphology: Properties from the morphology layer. 134 pool_layer_name: Name for the new layer to be created. 135 pool_name: Name for the pooled group to be assigned. 136 query: Query parameters. 137 pool_color: Optional color for the vesicle pool. 138 distances2: Properties from the second distances layer (optional). 139 """ 140 # Check which of the properties are present and construct the combined properties based on this. 141 if distances is None and morphology is None: # No properties were given -> we can't do anything. 142 show_info("ERROR: Neither distances nor vesicle morphology were found.") 143 return 144 elif distances is None and morphology is not None: # Only morphology props were found. 145 merged_df = pd.DataFrame(morphology).drop(columns=["index"], errors="ignore") 146 elif distances is not None and morphology is None: # Only distances were found. 147 merged_df = pd.DataFrame(distances).drop(columns=["index"], errors="ignore") 148 else: # Both were found. 149 distance_ids = distances.get("label", []) 150 morphology_ids = morphology.get("label", []) 151 152 # Ensure that IDs are identical. 153 if set(distance_ids) != set(morphology_ids): 154 show_info("ERROR: The IDs in distances and morphology are not identical.") 155 return 156 157 # Create a merged dataframe from the dataframes which are relevant for the criterion. 158 distances = pd.DataFrame(distances).drop(columns=["index"]) 159 morphology = pd.DataFrame(morphology).drop(columns=["index"]) 160 merged_df = morphology.merge(distances, left_on="label", right_on="label", suffixes=("_morph", "_dist")) 161 # Add distances2 if present. 162 if distances2 is not None: 163 distance_ids = distances2.get("label", []) 164 if set(distance_ids) != set(merged_df.label): 165 show_info("ERROR: The IDs in distances2 and morphology are not identical.") 166 return 167 distances2 = pd.DataFrame(distances2).drop(columns=["index"]) 168 merged_df = merged_df.merge(distances2, left_on="label", right_on="label", suffixes=("", "2")) 169 # Assign the vesicles to the current pool by filtering the mergeddataframe based on the query. 170 filtered_df = self._parse_query(query, merged_df) 171 if len(filtered_df) == 0: 172 show_info("No vesicles were found matching the condition.") 173 return 174 pool_vesicle_ids = filtered_df.label.values.tolist() 175 vesicles_in_pool = len(pool_vesicle_ids) 176 177 # Check if this layer was already created in a previous pool assignment. 178 if pool_layer_name in self.viewer.layers: 179 # If yes then load the previous pool assignments and merge them with the new pool assignments 180 pool_layer = self.viewer.layers[pool_layer_name] 181 pool_properties = pd.DataFrame.from_dict(pool_layer.properties) 182 183 pool_names = pd.unique(pool_properties.pool) 184 if pool_name in pool_names: 185 show_info(f"Updating pool '{pool_name}' with {vesicles_in_pool} vesicles.") 186 # This pool has already been assigned and we changed the criterion. 187 # Its old assignment has to be over-written, remove the rows for this pool. 188 pool_properties = pool_properties[pool_properties.pool != pool_name] 189 else: 190 show_info(f"Creating pool '{pool_name}' with {vesicles_in_pool} vesicles.") 191 192 # Combine the vesicle ids corresponding to the previous assignment with the 193 # assignment for the new / current pool. 194 old_pool_ids = pool_properties.label.values.tolist() 195 196 # Overwrite the intersection of the two pool assignments with the new pool. 197 pool_intersections = np.intersect1d(pool_vesicle_ids, old_pool_ids) 198 old_pool_ids = [item for item in old_pool_ids if item not in pool_intersections] 199 pool_properties = pool_properties[~pool_properties["label"].isin(pool_intersections)] 200 201 pool_assignments = sorted(pool_vesicle_ids + old_pool_ids) 202 203 # Get a map for each vesicle id to its pool. 204 id_to_pool_name = {ves_id: pool_name for ves_id in pool_vesicle_ids} 205 id_to_pool_name.update({k: v for k, v in zip(old_pool_ids, pool_properties.pool.values)}) 206 207 # Get the pool values. 208 # This is the list of pool names, corresponding to the selected ids in pool_assignments. 209 pool_values = [id_to_pool_name[ves_id] for ves_id in pool_assignments] 210 211 else: 212 show_info(f"Creating pool '{pool_name}' with {vesicles_in_pool} vesicles.") 213 # Otherwise, this is the first pool assignment. 214 pool_assignments = pool_vesicle_ids 215 pool_values = [pool_name] * len(pool_assignments) 216 217 # Create the filtered segmentation. 218 vesicle_pools = segmentation.copy() 219 vesicle_pools[~np.isin(vesicle_pools, pool_assignments)] = 0 220 221 # Create the pool properties. 222 pool_properties = merged_df[merged_df.label.isin(pool_assignments)] 223 # Remove columns that are not relevant for measurements. 224 keep_columns = [ 225 col for col in pool_properties.columns 226 if col not in ("x", "y", "z", "begin-x", "begin-y", "begin-z", "end-x", "end-y", "end-z") 227 ] 228 pool_properties = pool_properties[keep_columns] 229 # Add a colun for the pool. 230 pool_properties.insert(1, "pool", pool_values) 231 232 # Update the colormap to display the pools. 233 self._update_pool_colors(pool_name, pool_color) 234 235 # Assign the vesicle ids to their pool color. 236 vesicle_colors = { 237 label_id: self.pool_colors[pname] for label_id, pname in zip( 238 pool_properties.label.values, pool_properties.pool.values 239 ) 240 } 241 vesicle_colors[None] = "gray" 242 243 # Add or replace the pool layer and properties. 244 if pool_layer_name in self.viewer.layers: 245 pool_layer = self.viewer.layers[pool_layer_name] 246 pool_layer.data = vesicle_pools 247 pool_layer.colormap = vesicle_colors 248 else: 249 pool_layer = self.viewer.add_labels(vesicle_pools, name=pool_layer_name, colormap=vesicle_colors) 250 251 pool_properties = self._add_colors(pool_properties, vesicle_colors) 252 self._add_properties_and_table(pool_layer, pool_properties, save_path=self.save_path.text()) 253 pool_layer.refresh() 254 255 def _parse_query(self, query: str, data: pd.DataFrame) -> pd.DataFrame: 256 """Parse and apply a query string to filter data. 257 258 Args: 259 query: Comma-separated query string (e.g., "radius > 15, distance > 250"). 260 data: DataFrame containing the data to filter. 261 262 Returns: 263 Filtered DataFrame. 264 """ 265 filters = query.split(",") # Split the query into individual conditions 266 filters = [f.strip() for f in filters] # Remove extra spaces 267 for condition in filters: 268 try: 269 # Apply each condition to filter the DataFrame 270 data = data.query(condition) 271 except Exception as e: 272 print(f"Failed to apply condition '{condition}': {e}") 273 continue 274 return data 275 276 def _create_settings_widget(self): 277 setting_values = QWidget() 278 setting_values.setLayout(QVBoxLayout()) 279 280 self.save_path, layout = self._add_path_param(name="Save Table", select_type="file", value="") 281 setting_values.layout().addLayout(layout) 282 283 self.pool_color_param, layout = self._add_string_param(name="Pool Color", value="") 284 setting_values.layout().addLayout(layout) 285 286 settings = self._make_collapsible(widget=setting_values, title="Advanced Settings") 287 return settings
QWidget(parent: Optional[QWidget] = None, flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.WindowFlags())
def
on_pool_vesicles(self):
67 def on_pool_vesicles(self): 68 segmentation = self._get_layer_selector_data(self.vesicle_selector_name) 69 morphology = self._get_layer_selector_layer(self.vesicle_selector_name).properties 70 if not morphology: 71 morphology = None 72 73 distance_layer = self._get_layer_selector_layer(self.dist_selector_name1) 74 distances = None if distance_layer is None else distance_layer.properties 75 distance_layer2 = self._get_layer_selector_layer(self.dist_selector_name2) 76 # Check if the second distance is the same as the first. 77 if distance_layer2.name == distance_layer.name: 78 distance_layer2 = None 79 distances2 = None if distance_layer2 is None else distance_layer2.properties 80 81 if segmentation is None: 82 show_info("INFO: Please choose a segmentation.") 83 return 84 if self.query_param.text() == "": 85 show_info("INFO: Please enter a query string.") 86 return 87 query = self.query_param.text() 88 89 if self.pool_layer_name_param.text() == "": 90 show_info("INFO: Please enter a name for the pool layer.") 91 return 92 pool_layer_name = self.pool_layer_name_param.text() 93 if self.pool_name_param.text() == "": 94 show_info("INFO: Please enter a name for the vesicle pool.") 95 return 96 pool_name = self.pool_name_param.text() 97 98 pool_color = self.pool_color_param.text() 99 self._compute_vesicle_pool( 100 segmentation, distances, morphology, pool_layer_name, pool_name, query, pool_color, distances2 101 )