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']
class VesiclePoolWidget(synapse_net.tools.base_widget.BaseWidget):
 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())

viewer
vesicle_selector_name
vesicle_selector_widget
dist_selector_name1
dist_selector_widget1
dist_selector_name2
dist_selector_widget2
settings
measure_button
pool_colors
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            )