From 458ec9036faa7c981288a06410148e76b4dc1eaa Mon Sep 17 00:00:00 2001 From: lufre1 <155526548+lufre1@users.noreply.github.com> Date: Tue, 10 Dec 2024 13:50:52 +0100 Subject: [PATCH] 78 improvements to vesicle pool assignment widget (#81) Updates to vesicle pool widget --- synapse_net/tools/base_widget.py | 13 ++------- synapse_net/tools/distance_measure_widget.py | 3 +- synapse_net/tools/segmentation_widget.py | 2 +- synapse_net/tools/vesicle_pool_widget.py | 30 ++++++++++++++++++-- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/synapse_net/tools/base_widget.py b/synapse_net/tools/base_widget.py index 627d59f..bcf1f9c 100644 --- a/synapse_net/tools/base_widget.py +++ b/synapse_net/tools/base_widget.py @@ -330,17 +330,8 @@ def _add_properties_and_table(self, layer, table_data, save_path=""): layer.properties = table_data if add_table is not None: - table = get_table(layer, self.viewer) - if table is None: - with _SilencePrint(): - add_table(layer, self.viewer) - else: - # FIXME updating the table does not yet work - with _SilencePrint(): - table.update_content() - # table_dict = table_data.to_dict() - # table_dict["index"] = table_dict["label"] - # table.set_content(table_dict) + with _SilencePrint(): + add_table(layer, self.viewer) # Save table to file if save path is provided. if save_path != "": diff --git a/synapse_net/tools/distance_measure_widget.py b/synapse_net/tools/distance_measure_widget.py index cbe012b..6f721ca 100644 --- a/synapse_net/tools/distance_measure_widget.py +++ b/synapse_net/tools/distance_measure_widget.py @@ -87,7 +87,8 @@ def on_measure_seg_to_object(self): seg_ids=seg_ids, ) table_data = self._to_table_data(distances, seg_ids, endpoints1, endpoints2) - self._add_lines_and_table(lines, table_data, name="distances") + structure_layer_name = self._get_layer_selector_layer(self.image_selector_name2).name + self._add_lines_and_table(lines, table_data, name="distances-to-" + structure_layer_name) def on_measure_pairwise(self): segmentation = self._get_layer_selector_data(self.image_selector_name1) diff --git a/synapse_net/tools/segmentation_widget.py b/synapse_net/tools/segmentation_widget.py index 6fbb0cc..f74e078 100644 --- a/synapse_net/tools/segmentation_widget.py +++ b/synapse_net/tools/segmentation_widget.py @@ -116,7 +116,7 @@ def on_predict(self): for name, seg in segmentation.items(): self.viewer.add_labels(seg, name=name, metadata=metadata) else: - self.viewer.add_labels(segmentation, name=f"{model_type}-segmentation", metadata=metadata) + self.viewer.add_labels(segmentation, name=f"{model_type}", metadata=metadata) show_info(f"INFO: Segmentation of {model_type} added to layers.") def _create_settings_widget(self): diff --git a/synapse_net/tools/vesicle_pool_widget.py b/synapse_net/tools/vesicle_pool_widget.py index 379a9de..2e95e5d 100644 --- a/synapse_net/tools/vesicle_pool_widget.py +++ b/synapse_net/tools/vesicle_pool_widget.py @@ -30,10 +30,14 @@ def __init__(self): # 2. Selector for a distance layer. self.dist_selector_name1 = "Distances to Structure" self.dist_selector_widget1 = self._create_layer_selector(self.dist_selector_name1, layer_type="Shapes") + # 3. Selector for a second distance layer (optional). + self.dist_selector_name2 = "Distances to Structure 2" + self.dist_selector_widget2 = self._create_layer_selector(self.dist_selector_name2, layer_type="Shapes") # Add the selector widgets to the layout. layout.addWidget(self.vesicle_selector_widget) layout.addWidget(self.dist_selector_widget1) + layout.addWidget(self.dist_selector_widget2) # Create the UI elements for defining the vesicle pools: # The name of the output name, the name of the vesicle pool, and the criterion for the pool. @@ -68,6 +72,11 @@ def on_pool_vesicles(self): distance_layer = self._get_layer_selector_layer(self.dist_selector_name1) distances = None if distance_layer is None else distance_layer.properties + distance_layer2 = self._get_layer_selector_layer(self.dist_selector_name2) + # Check if the second distance is the same as the first. + if distance_layer2.name == distance_layer.name: + distance_layer2 = None + distances2 = None if distance_layer2 is None else distance_layer2.properties if segmentation is None: show_info("INFO: Please choose a segmentation.") @@ -87,7 +96,9 @@ def on_pool_vesicles(self): pool_name = self.pool_name_param.text() pool_color = self.pool_color_param.text() - self._compute_vesicle_pool(segmentation, distances, morphology, pool_layer_name, pool_name, query, pool_color) + self._compute_vesicle_pool( + segmentation, distances, morphology, pool_layer_name, pool_name, query, pool_color, distances2 + ) def _update_pool_colors(self, pool_name, pool_color): if pool_color == "": @@ -107,6 +118,7 @@ def _compute_vesicle_pool( pool_name: str, query: str, pool_color: str, + distances2: Dict = None ): """Compute a vesicle pool based on the provided query parameters. @@ -118,6 +130,7 @@ def _compute_vesicle_pool( pool_name: Name for the pooled group to be assigned. query: Query parameters. pool_color: Optional color for the vesicle pool. + distances2: Properties from the second distances layer (optional). """ # Check which of the properties are present and construct the combined properties based on this. if distances is None and morphology is None: # No properties were given -> we can't do anything. @@ -140,7 +153,14 @@ def _compute_vesicle_pool( distances = pd.DataFrame(distances).drop(columns=["index"]) morphology = pd.DataFrame(morphology).drop(columns=["index"]) merged_df = morphology.merge(distances, left_on="label", right_on="label", suffixes=("_morph", "_dist")) - + # Add distances2 if present. + if distances2 is not None: + distance_ids = distances2.get("label", []) + if set(distance_ids) != set(merged_df.label): + show_info("ERROR: The IDs in distances2 and morphology are not identical.") + return + distances2 = pd.DataFrame(distances2).drop(columns=["index"]) + merged_df = merged_df.merge(distances2, left_on="label", right_on="label", suffixes=("", "2")) # Assign the vesicles to the current pool by filtering the mergeddataframe based on the query. filtered_df = self._parse_query(query, merged_df) if len(filtered_df) == 0: @@ -167,6 +187,12 @@ def _compute_vesicle_pool( # Combine the vesicle ids corresponding to the previous assignment with the # assignment for the new / current pool. old_pool_ids = pool_properties.label.values.tolist() + + # Overwrite the intersection of the two pool assignments with the new pool. + pool_intersections = np.intersect1d(pool_vesicle_ids, old_pool_ids) + old_pool_ids = [item for item in old_pool_ids if item not in pool_intersections] + pool_properties = pool_properties[~pool_properties['label'].isin(pool_intersections)] + pool_assignments = sorted(pool_vesicle_ids + old_pool_ids) # Get a map for each vesicle id to its pool.