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 _compute_vesicle_pool( 112 self, 113 segmentation: np.ndarray, 114 distances: Dict, 115 morphology: Dict, 116 pool_layer_name: str, 117 pool_name: str, 118 query: str, 119 pool_color: str, 120 distances2: Dict = None 121 ): 122 """Compute a vesicle pool based on the provided query parameters. 123 124 Args: 125 segmentation: Segmentation data (e.g., labeled regions). 126 distances: Properties from the distances layer. 127 morphology: Properties from the morphology layer. 128 pool_layer_name: Name for the new layer to be created. 129 pool_name: Name for the pooled group to be assigned. 130 query: Query parameters. 131 pool_color: Optional color for the vesicle pool. 132 distances2: Properties from the second distances layer (optional). 133 """ 134 # Check which of the properties are present and construct the combined properties based on this. 135 if distances is None and morphology is None: # No properties were given -> we can't do anything. 136 show_info("ERROR: Neither distances nor vesicle morphology were found.") 137 return 138 elif distances is None and morphology is not None: # Only morphology props were found. 139 merged_df = pd.DataFrame(morphology).drop(columns=["index"]) 140 elif distances is not None and morphology is None: # Only distances were found. 141 merged_df = pd.DataFrame(distances).drop(columns=["index"]) 142 else: # Both were found. 143 distance_ids = distances.get("label", []) 144 morphology_ids = morphology.get("label", []) 145 146 # Ensure that IDs are identical. 147 if set(distance_ids) != set(morphology_ids): 148 show_info("ERROR: The IDs in distances and morphology are not identical.") 149 return 150 151 # Create a merged dataframe from the dataframes which are relevant for the criterion. 152 distances = pd.DataFrame(distances).drop(columns=["index"]) 153 morphology = pd.DataFrame(morphology).drop(columns=["index"]) 154 merged_df = morphology.merge(distances, left_on="label", right_on="label", suffixes=("_morph", "_dist")) 155 # Add distances2 if present. 156 if distances2 is not None: 157 distance_ids = distances2.get("label", []) 158 if set(distance_ids) != set(merged_df.label): 159 show_info("ERROR: The IDs in distances2 and morphology are not identical.") 160 return 161 distances2 = pd.DataFrame(distances2).drop(columns=["index"]) 162 merged_df = merged_df.merge(distances2, left_on="label", right_on="label", suffixes=("", "2")) 163 # Assign the vesicles to the current pool by filtering the mergeddataframe based on the query. 164 filtered_df = self._parse_query(query, merged_df) 165 if len(filtered_df) == 0: 166 show_info("No vesicles were found matching the condition.") 167 return 168 pool_vesicle_ids = filtered_df.label.values.tolist() 169 vesicles_in_pool = len(pool_vesicle_ids) 170 171 # Check if this layer was already created in a previous pool assignment. 172 if pool_layer_name in self.viewer.layers: 173 # If yes then load the previous pool assignments and merge them with the new pool assignments 174 pool_layer = self.viewer.layers[pool_layer_name] 175 pool_properties = pd.DataFrame.from_dict(pool_layer.properties) 176 177 pool_names = pd.unique(pool_properties.pool) 178 if pool_name in pool_names: 179 show_info(f"Updating pool '{pool_name}' with {vesicles_in_pool} vesicles.") 180 # This pool has already been assigned and we changed the criterion. 181 # Its old assignment has to be over-written, remove the rows for this pool. 182 pool_properties = pool_properties[pool_properties.pool != pool_name] 183 else: 184 show_info(f"Creating pool '{pool_name}' with {vesicles_in_pool} vesicles.") 185 186 # Combine the vesicle ids corresponding to the previous assignment with the 187 # assignment for the new / current pool. 188 old_pool_ids = pool_properties.label.values.tolist() 189 190 # Overwrite the intersection of the two pool assignments with the new pool. 191 pool_intersections = np.intersect1d(pool_vesicle_ids, old_pool_ids) 192 old_pool_ids = [item for item in old_pool_ids if item not in pool_intersections] 193 pool_properties = pool_properties[~pool_properties['label'].isin(pool_intersections)] 194 195 pool_assignments = sorted(pool_vesicle_ids + old_pool_ids) 196 197 # Get a map for each vesicle id to its pool. 198 id_to_pool_name = {ves_id: pool_name for ves_id in pool_vesicle_ids} 199 id_to_pool_name.update({k: v for k, v in zip(old_pool_ids, pool_properties.pool.values)}) 200 201 # Get the pool values. 202 # This is the list of pool names, corresponding to the selected ids in pool_assignments. 203 pool_values = [id_to_pool_name[ves_id] for ves_id in pool_assignments] 204 205 else: 206 show_info(f"Creating pool '{pool_name}' with {vesicles_in_pool} vesicles.") 207 # Otherwise, this is the first pool assignment. 208 pool_assignments = pool_vesicle_ids 209 pool_values = [pool_name] * len(pool_assignments) 210 211 # Create the filtered segmentation. 212 vesicle_pools = segmentation.copy() 213 vesicle_pools[~np.isin(vesicle_pools, pool_assignments)] = 0 214 215 # Create the pool properties. 216 pool_properties = merged_df[merged_df.label.isin(pool_assignments)] 217 # Remove columns that are not relevant for measurements. 218 keep_columns = [ 219 col for col in pool_properties.columns 220 if col not in ("x", "y", "z", "begin-x", "begin-y", "begin-z", "end-x", "end-y", "end-z") 221 ] 222 pool_properties = pool_properties[keep_columns] 223 # Add a colun for the pool. 224 pool_properties.insert(1, "pool", pool_values) 225 226 # Update the colormap to display the pools. 227 self._update_pool_colors(pool_name, pool_color) 228 229 # Assign the vesicle ids to their pool color. 230 vesicle_colors = { 231 label_id: self.pool_colors[pname] for label_id, pname in zip( 232 pool_properties.label.values, pool_properties.pool.values 233 ) 234 } 235 vesicle_colors[None] = "gray" 236 237 # Add or replace the pool layer and properties. 238 if pool_layer_name in self.viewer.layers: 239 pool_layer = self.viewer.layers[pool_layer_name] 240 pool_layer.data = vesicle_pools 241 pool_layer.colormap = vesicle_colors 242 else: 243 pool_layer = self.viewer.add_labels(vesicle_pools, name=pool_layer_name, colormap=vesicle_colors) 244 245 self._add_properties_and_table(pool_layer, pool_properties, save_path=self.save_path.text()) 246 pool_layer.refresh() 247 248 def _parse_query(self, query: str, data: pd.DataFrame) -> pd.DataFrame: 249 """Parse and apply a query string to filter data. 250 251 Args: 252 query: Comma-separated query string (e.g., "radius > 15, distance > 250"). 253 data: DataFrame containing the data to filter. 254 255 Returns: 256 Filtered DataFrame. 257 """ 258 filters = query.split(",") # Split the query into individual conditions 259 filters = [f.strip() for f in filters] # Remove extra spaces 260 for condition in filters: 261 try: 262 # Apply each condition to filter the DataFrame 263 data = data.query(condition) 264 except Exception as e: 265 print(f"Failed to apply condition '{condition}': {e}") 266 continue 267 return data 268 269 def _create_settings_widget(self): 270 setting_values = QWidget() 271 setting_values.setLayout(QVBoxLayout()) 272 273 self.save_path, layout = self._add_path_param(name="Save Table", select_type="file", value="") 274 setting_values.layout().addLayout(layout) 275 276 self.pool_color_param, layout = self._add_string_param(name="Pool Color", value="") 277 setting_values.layout().addLayout(layout) 278 279 settings = self._make_collapsible(widget=setting_values, title="Advanced Settings") 280 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 _compute_vesicle_pool( 113 self, 114 segmentation: np.ndarray, 115 distances: Dict, 116 morphology: Dict, 117 pool_layer_name: str, 118 pool_name: str, 119 query: str, 120 pool_color: str, 121 distances2: Dict = None 122 ): 123 """Compute a vesicle pool based on the provided query parameters. 124 125 Args: 126 segmentation: Segmentation data (e.g., labeled regions). 127 distances: Properties from the distances layer. 128 morphology: Properties from the morphology layer. 129 pool_layer_name: Name for the new layer to be created. 130 pool_name: Name for the pooled group to be assigned. 131 query: Query parameters. 132 pool_color: Optional color for the vesicle pool. 133 distances2: Properties from the second distances layer (optional). 134 """ 135 # Check which of the properties are present and construct the combined properties based on this. 136 if distances is None and morphology is None: # No properties were given -> we can't do anything. 137 show_info("ERROR: Neither distances nor vesicle morphology were found.") 138 return 139 elif distances is None and morphology is not None: # Only morphology props were found. 140 merged_df = pd.DataFrame(morphology).drop(columns=["index"]) 141 elif distances is not None and morphology is None: # Only distances were found. 142 merged_df = pd.DataFrame(distances).drop(columns=["index"]) 143 else: # Both were found. 144 distance_ids = distances.get("label", []) 145 morphology_ids = morphology.get("label", []) 146 147 # Ensure that IDs are identical. 148 if set(distance_ids) != set(morphology_ids): 149 show_info("ERROR: The IDs in distances and morphology are not identical.") 150 return 151 152 # Create a merged dataframe from the dataframes which are relevant for the criterion. 153 distances = pd.DataFrame(distances).drop(columns=["index"]) 154 morphology = pd.DataFrame(morphology).drop(columns=["index"]) 155 merged_df = morphology.merge(distances, left_on="label", right_on="label", suffixes=("_morph", "_dist")) 156 # Add distances2 if present. 157 if distances2 is not None: 158 distance_ids = distances2.get("label", []) 159 if set(distance_ids) != set(merged_df.label): 160 show_info("ERROR: The IDs in distances2 and morphology are not identical.") 161 return 162 distances2 = pd.DataFrame(distances2).drop(columns=["index"]) 163 merged_df = merged_df.merge(distances2, left_on="label", right_on="label", suffixes=("", "2")) 164 # Assign the vesicles to the current pool by filtering the mergeddataframe based on the query. 165 filtered_df = self._parse_query(query, merged_df) 166 if len(filtered_df) == 0: 167 show_info("No vesicles were found matching the condition.") 168 return 169 pool_vesicle_ids = filtered_df.label.values.tolist() 170 vesicles_in_pool = len(pool_vesicle_ids) 171 172 # Check if this layer was already created in a previous pool assignment. 173 if pool_layer_name in self.viewer.layers: 174 # If yes then load the previous pool assignments and merge them with the new pool assignments 175 pool_layer = self.viewer.layers[pool_layer_name] 176 pool_properties = pd.DataFrame.from_dict(pool_layer.properties) 177 178 pool_names = pd.unique(pool_properties.pool) 179 if pool_name in pool_names: 180 show_info(f"Updating pool '{pool_name}' with {vesicles_in_pool} vesicles.") 181 # This pool has already been assigned and we changed the criterion. 182 # Its old assignment has to be over-written, remove the rows for this pool. 183 pool_properties = pool_properties[pool_properties.pool != pool_name] 184 else: 185 show_info(f"Creating pool '{pool_name}' with {vesicles_in_pool} vesicles.") 186 187 # Combine the vesicle ids corresponding to the previous assignment with the 188 # assignment for the new / current pool. 189 old_pool_ids = pool_properties.label.values.tolist() 190 191 # Overwrite the intersection of the two pool assignments with the new pool. 192 pool_intersections = np.intersect1d(pool_vesicle_ids, old_pool_ids) 193 old_pool_ids = [item for item in old_pool_ids if item not in pool_intersections] 194 pool_properties = pool_properties[~pool_properties['label'].isin(pool_intersections)] 195 196 pool_assignments = sorted(pool_vesicle_ids + old_pool_ids) 197 198 # Get a map for each vesicle id to its pool. 199 id_to_pool_name = {ves_id: pool_name for ves_id in pool_vesicle_ids} 200 id_to_pool_name.update({k: v for k, v in zip(old_pool_ids, pool_properties.pool.values)}) 201 202 # Get the pool values. 203 # This is the list of pool names, corresponding to the selected ids in pool_assignments. 204 pool_values = [id_to_pool_name[ves_id] for ves_id in pool_assignments] 205 206 else: 207 show_info(f"Creating pool '{pool_name}' with {vesicles_in_pool} vesicles.") 208 # Otherwise, this is the first pool assignment. 209 pool_assignments = pool_vesicle_ids 210 pool_values = [pool_name] * len(pool_assignments) 211 212 # Create the filtered segmentation. 213 vesicle_pools = segmentation.copy() 214 vesicle_pools[~np.isin(vesicle_pools, pool_assignments)] = 0 215 216 # Create the pool properties. 217 pool_properties = merged_df[merged_df.label.isin(pool_assignments)] 218 # Remove columns that are not relevant for measurements. 219 keep_columns = [ 220 col for col in pool_properties.columns 221 if col not in ("x", "y", "z", "begin-x", "begin-y", "begin-z", "end-x", "end-y", "end-z") 222 ] 223 pool_properties = pool_properties[keep_columns] 224 # Add a colun for the pool. 225 pool_properties.insert(1, "pool", pool_values) 226 227 # Update the colormap to display the pools. 228 self._update_pool_colors(pool_name, pool_color) 229 230 # Assign the vesicle ids to their pool color. 231 vesicle_colors = { 232 label_id: self.pool_colors[pname] for label_id, pname in zip( 233 pool_properties.label.values, pool_properties.pool.values 234 ) 235 } 236 vesicle_colors[None] = "gray" 237 238 # Add or replace the pool layer and properties. 239 if pool_layer_name in self.viewer.layers: 240 pool_layer = self.viewer.layers[pool_layer_name] 241 pool_layer.data = vesicle_pools 242 pool_layer.colormap = vesicle_colors 243 else: 244 pool_layer = self.viewer.add_labels(vesicle_pools, name=pool_layer_name, colormap=vesicle_colors) 245 246 self._add_properties_and_table(pool_layer, pool_properties, save_path=self.save_path.text()) 247 pool_layer.refresh() 248 249 def _parse_query(self, query: str, data: pd.DataFrame) -> pd.DataFrame: 250 """Parse and apply a query string to filter data. 251 252 Args: 253 query: Comma-separated query string (e.g., "radius > 15, distance > 250"). 254 data: DataFrame containing the data to filter. 255 256 Returns: 257 Filtered DataFrame. 258 """ 259 filters = query.split(",") # Split the query into individual conditions 260 filters = [f.strip() for f in filters] # Remove extra spaces 261 for condition in filters: 262 try: 263 # Apply each condition to filter the DataFrame 264 data = data.query(condition) 265 except Exception as e: 266 print(f"Failed to apply condition '{condition}': {e}") 267 continue 268 return data 269 270 def _create_settings_widget(self): 271 setting_values = QWidget() 272 setting_values.setLayout(QVBoxLayout()) 273 274 self.save_path, layout = self._add_path_param(name="Save Table", select_type="file", value="") 275 setting_values.layout().addLayout(layout) 276 277 self.pool_color_param, layout = self._add_string_param(name="Pool Color", value="") 278 setting_values.layout().addLayout(layout) 279 280 settings = self._make_collapsible(widget=setting_values, title="Advanced Settings") 281 return settings
QWidget(parent: typing.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 )