From 20fd5984c196ea2d96baef9249e501001c3f2be8 Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Wed, 29 Jan 2025 10:32:13 -0800 Subject: [PATCH 01/25] prediction_result_list_widget --- .../core/prediction_result_input_widget.py | 45 +++++++++++++++++++ src/allencell_ml_segmenter/prediction/view.py | 4 +- 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/allencell_ml_segmenter/core/prediction_result_input_widget.py diff --git a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py new file mode 100644 index 00000000..93d59223 --- /dev/null +++ b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py @@ -0,0 +1,45 @@ +from allencell_ml_segmenter.core.file_input_model import ( + InputMode, + FileInputModel, +) +from allencell_ml_segmenter.core.file_input_widget import FileInputWidget +from allencell_ml_segmenter.main.i_viewer import IViewer +from allencell_ml_segmenter.main.segmenter_layer import LabelsLayer +from qtpy.QtCore import Qt + +from allencell_ml_segmenter.prediction.service import ModelFileService + + +class PredictionResultListWidget(FileInputWidget): + """ + Widget containing a list of prediction results that are selectable for thresholding + """ + + def __init__( + self, model: FileInputModel, viewer: IViewer, service: ModelFileService + ): + super().__init__( + model, viewer, service, include_channel_selection=False + ) + self._prediction_layers: list[LabelsLayer] = ( + self._viewer.get_all_segmentation_labels() + ) + + def _update_layer_list(self) -> None: + self._image_list.clear() + self._reset_channel_combobox() + self._prediction_layers = self._viewer.get_all_segmentation_labels() + for prediction_output_layer in self._prediction_layers: + self._image_list.add_item( + prediction_output_layer.name, + ) + + def process_checked_signal(self, row: int, state: Qt.CheckState) -> None: + if self._model.get_input_mode() == InputMode.FROM_NAPARI_LAYERS: + selected_indices: list[int] = self._image_list.get_checked_rows() + if state == Qt.CheckState.Checked: + # paths of images to be segmented, which will not be opened again because already in memory + # but satisfies file_input_model state which determines if we have anything selected + self._model.set_selected_paths( + [x.path for x in self._prediction_layers] + ) diff --git a/src/allencell_ml_segmenter/prediction/view.py b/src/allencell_ml_segmenter/prediction/view.py index 29eda78d..e5a0b448 100644 --- a/src/allencell_ml_segmenter/prediction/view.py +++ b/src/allencell_ml_segmenter/prediction/view.py @@ -202,8 +202,8 @@ def showResults(self) -> None: metadata={ "source_path": data["seg"], "prob_map": self._img_data_extractor.extract_image_data( - data["seg"] - ).np_data, + data["seg"], dims=True + ), }, ) From 980c05061a27d092bd84946b70a41ff6a7a65dca Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Wed, 29 Jan 2025 13:12:16 -0800 Subject: [PATCH 02/25] need this still --- .../core/prediction_result_input_widget.py | 1 - .../thresholding/thresholding_view.py | 15 ++++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py index 93d59223..729c16ce 100644 --- a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py +++ b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py @@ -27,7 +27,6 @@ def __init__( def _update_layer_list(self) -> None: self._image_list.clear() - self._reset_channel_combobox() self._prediction_layers = self._viewer.get_all_segmentation_labels() for prediction_output_layer in self._prediction_layers: self._image_list.add_item( diff --git a/src/allencell_ml_segmenter/thresholding/thresholding_view.py b/src/allencell_ml_segmenter/thresholding/thresholding_view.py index 958435ce..6143007c 100644 --- a/src/allencell_ml_segmenter/thresholding/thresholding_view.py +++ b/src/allencell_ml_segmenter/thresholding/thresholding_view.py @@ -21,8 +21,8 @@ from allencell_ml_segmenter.utils.file_utils import FileUtils from allencell_ml_segmenter.widgets.label_with_hint_widget import LabelWithHint -from allencell_ml_segmenter.core.file_input_widget import ( - FileInputWidget, +from allencell_ml_segmenter.core.prediction_result_input_widget import ( + PredictionResultListWidget, ) from allencell_ml_segmenter.core.file_input_model import ( FileInputModel, @@ -44,6 +44,8 @@ from qtpy.QtCore import Qt + + class ThresholdingView(View, MainWindow): """ View for thresholding @@ -85,14 +87,13 @@ def __init__( layout.addWidget(self._title, alignment=Qt.AlignmentFlag.AlignHCenter) # selecting input image - self._file_input_widget: FileInputWidget = FileInputWidget( + self._prediction_result_input_widget: PredictionResultListWidget = PredictionResultListWidget( self._file_input_model, self._viewer, self._input_files_service, - include_channel_selection=False, ) - self._file_input_widget.setObjectName("fileInput") - layout.addWidget(self._file_input_widget) + self._prediction_result_input_widget.setObjectName("fileInput") + layout.addWidget(self._prediction_result_input_widget) # thresholding values self._threshold_label: LabelWithHint = LabelWithHint("Threshold") @@ -326,7 +327,7 @@ def doWork(self) -> None: self._thresholding_model.dispatch_save_thresholded_images() def focus_changed(self) -> None: - self._file_input_widget._update_layer_list() + self._prediction_result_input_widget._update_layer_list() def getTypeOfWork(self) -> str: return "" From 4147232f25f5a47e6957b912c2c63f73c9d15cd2 Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Wed, 29 Jan 2025 13:27:23 -0800 Subject: [PATCH 03/25] use imagedata --- src/allencell_ml_segmenter/thresholding/thresholding_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/allencell_ml_segmenter/thresholding/thresholding_service.py b/src/allencell_ml_segmenter/thresholding/thresholding_service.py index c93f9f3e..4e82b4cf 100644 --- a/src/allencell_ml_segmenter/thresholding/thresholding_service.py +++ b/src/allencell_ml_segmenter/thresholding/thresholding_service.py @@ -93,7 +93,7 @@ def thresholding_task() -> np.ndarray: "Layer metadata must be a dictionary containing the 'prob_map' key in order to threshold." ) - return thresh_function(layer.metadata["prob_map"]) + return thresh_function(layer.metadata["prob_map"].data) layer_instance: LabelsLayer = layer From fc68eb81a724d1d7cede2d7af0d1fcfacaedd123 Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Wed, 29 Jan 2025 13:32:41 -0800 Subject: [PATCH 04/25] oops, should be ImageData.np_data not ImageData.data --- src/allencell_ml_segmenter/thresholding/thresholding_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/allencell_ml_segmenter/thresholding/thresholding_service.py b/src/allencell_ml_segmenter/thresholding/thresholding_service.py index 4e82b4cf..54cd549a 100644 --- a/src/allencell_ml_segmenter/thresholding/thresholding_service.py +++ b/src/allencell_ml_segmenter/thresholding/thresholding_service.py @@ -93,7 +93,7 @@ def thresholding_task() -> np.ndarray: "Layer metadata must be a dictionary containing the 'prob_map' key in order to threshold." ) - return thresh_function(layer.metadata["prob_map"].data) + return thresh_function(layer.metadata["prob_map"].np_data) layer_instance: LabelsLayer = layer From 33c003e3f8524577b7aa21aab36941bc8956e423 Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Wed, 29 Jan 2025 13:44:58 -0800 Subject: [PATCH 05/25] change way we insert a new segmentation threshold layer --- src/allencell_ml_segmenter/main/viewer.py | 32 ++++--------------- .../thresholding/thresholding_service.py | 2 +- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/src/allencell_ml_segmenter/main/viewer.py b/src/allencell_ml_segmenter/main/viewer.py index c3b94e85..1aff1eb0 100644 --- a/src/allencell_ml_segmenter/main/viewer.py +++ b/src/allencell_ml_segmenter/main/viewer.py @@ -143,7 +143,7 @@ def get_seg_layers(self) -> list[Layer]: def insert_threshold( self, - layer_name: str, + layer: Layer, image: np.ndarray, remove_seg_layers: bool = False, ) -> None: @@ -153,33 +153,13 @@ def insert_threshold( If the layer does not exist, it will be added to the viewer in the correct place (on top of the original segmentation image: index_of_segmentation + 1 in the LayerList) - :param layer_name: name of layer to insert. Will replace if one exists, will create one in a new position if needed. + :param layer: layer to replace. :param image: image to insert :param remove_seg_layers: boolean indicating if the layer that is being thresholded is a segmentation layer, and should be removed from the layer once it is updated with the threshold. """ - layer_to_insert = self._get_layer_by_name(f"[threshold] {layer_name}") - if layer_to_insert is None: - # No thresholding exists, so we add it to the correct place in the viewer - layerlist = self.viewer.layers - - # check if the original segementation layer is currently in the viewer, if so, remove later after - # thresholding is applied - seg_layer_og: Optional[Layer] = None - if remove_seg_layers: - seg_layer_og = self._get_layer_by_name(layer_name) - - # figure out where to insert the new thresholded layer (on top of the original segmentation image) - layerlist_pos = layerlist.index(layer_name) - labels_created = Labels(image, name=f"[threshold] {layer_name}") - layerlist.insert(layerlist_pos + 1, labels_created) - - # remove the original segmentation layer if it exists - if seg_layer_og: - layerlist.remove(seg_layer_og) - else: - # Thresholding already exists so just update the existing one in the viewer. - layer_to_insert.data = image - layer_to_insert.refresh() + layer.name = f"[threshold] {layer.name}" + layer.data = image + layer.refresh() def get_source_path(self, layer: Layer) -> Optional[Path]: """ @@ -193,7 +173,7 @@ def get_source_path(self, layer: Layer) -> Optional[Path]: return Path(layer.metadata["source_path"]) return None - def get_all_segmentation_labels(self) -> list[LabelsLayer]: + def get_all_segmentation_labels(self) -> list[Layer]: """ Get all segmentation labels layers that currently exist in the viewer. """ diff --git a/src/allencell_ml_segmenter/thresholding/thresholding_service.py b/src/allencell_ml_segmenter/thresholding/thresholding_service.py index 54cd549a..25da925f 100644 --- a/src/allencell_ml_segmenter/thresholding/thresholding_service.py +++ b/src/allencell_ml_segmenter/thresholding/thresholding_service.py @@ -101,7 +101,7 @@ def on_return( threshold_output: np.ndarray, ) -> None: self._viewer.insert_threshold( - layer_instance.name, + layer_instance, threshold_output, self._main_model.are_predictions_in_viewer(), ) From c7f13cd3ad21d67dc489ccdc0d1236cd394c11bb Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Wed, 29 Jan 2025 13:49:48 -0800 Subject: [PATCH 06/25] prepend [threshold] to layer name only if this is the first time a threshold has been applied --- src/allencell_ml_segmenter/main/viewer.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/allencell_ml_segmenter/main/viewer.py b/src/allencell_ml_segmenter/main/viewer.py index 1aff1eb0..7c5c2845 100644 --- a/src/allencell_ml_segmenter/main/viewer.py +++ b/src/allencell_ml_segmenter/main/viewer.py @@ -157,8 +157,11 @@ def insert_threshold( :param image: image to insert :param remove_seg_layers: boolean indicating if the layer that is being thresholded is a segmentation layer, and should be removed from the layer once it is updated with the threshold. """ - layer.name = f"[threshold] {layer.name}" + # if threshold has not been previously applied, update name + if not layer.metadata["threshold_applied"]: + layer.name = f"[threshold] {layer.name}" layer.data = image + layer.metadata["threshold_applied"] = True layer.refresh() def get_source_path(self, layer: Layer) -> Optional[Path]: From ae26f80daabccfab0f090a901d690aba9442ef5d Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Wed, 29 Jan 2025 13:52:58 -0800 Subject: [PATCH 07/25] no key check for dictionary --- src/allencell_ml_segmenter/main/viewer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/allencell_ml_segmenter/main/viewer.py b/src/allencell_ml_segmenter/main/viewer.py index 7c5c2845..e2df1521 100644 --- a/src/allencell_ml_segmenter/main/viewer.py +++ b/src/allencell_ml_segmenter/main/viewer.py @@ -158,7 +158,7 @@ def insert_threshold( :param remove_seg_layers: boolean indicating if the layer that is being thresholded is a segmentation layer, and should be removed from the layer once it is updated with the threshold. """ # if threshold has not been previously applied, update name - if not layer.metadata["threshold_applied"]: + if "threshold_applied" in layer.metadata and not layer.metadata["threshold_applied"]: layer.name = f"[threshold] {layer.name}" layer.data = image layer.metadata["threshold_applied"] = True From 0af12e6f952dbfb24c060c1943f2e064a6acf9fa Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Wed, 29 Jan 2025 14:01:14 -0800 Subject: [PATCH 08/25] no key check for dictionary --- src/allencell_ml_segmenter/main/viewer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/allencell_ml_segmenter/main/viewer.py b/src/allencell_ml_segmenter/main/viewer.py index e2df1521..48f4ae22 100644 --- a/src/allencell_ml_segmenter/main/viewer.py +++ b/src/allencell_ml_segmenter/main/viewer.py @@ -158,7 +158,7 @@ def insert_threshold( :param remove_seg_layers: boolean indicating if the layer that is being thresholded is a segmentation layer, and should be removed from the layer once it is updated with the threshold. """ # if threshold has not been previously applied, update name - if "threshold_applied" in layer.metadata and not layer.metadata["threshold_applied"]: + if "threshold_applied" not in layer.metadata: layer.name = f"[threshold] {layer.name}" layer.data = image layer.metadata["threshold_applied"] = True From 92ba3fa4cbd5ee53c1d94321bef6d5c6900639e3 Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Wed, 29 Jan 2025 14:08:55 -0800 Subject: [PATCH 09/25] init prediction layers as empty- since for now we will not have any prediction layers on plugin startup --- .../core/prediction_result_input_widget.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py index 729c16ce..96111318 100644 --- a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py +++ b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py @@ -21,9 +21,7 @@ def __init__( super().__init__( model, viewer, service, include_channel_selection=False ) - self._prediction_layers: list[LabelsLayer] = ( - self._viewer.get_all_segmentation_labels() - ) + self._prediction_layers: list[LabelsLayer] = [] def _update_layer_list(self) -> None: self._image_list.clear() From a45fbb28246585ba809f47ff246dd6b59abddbca Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Wed, 29 Jan 2025 14:30:01 -0800 Subject: [PATCH 10/25] dont store ImageData object, can just store np.data directly --- src/allencell_ml_segmenter/_tests/fakes/fake_viewer.py | 6 +++--- src/allencell_ml_segmenter/main/i_viewer.py | 2 +- src/allencell_ml_segmenter/prediction/view.py | 4 ++-- .../thresholding/thresholding_service.py | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/allencell_ml_segmenter/_tests/fakes/fake_viewer.py b/src/allencell_ml_segmenter/_tests/fakes/fake_viewer.py index d08b67d5..8797825a 100644 --- a/src/allencell_ml_segmenter/_tests/fakes/fake_viewer.py +++ b/src/allencell_ml_segmenter/_tests/fakes/fake_viewer.py @@ -119,9 +119,9 @@ def get_seg_layers(self) -> list[Layer]: ] def insert_threshold( - self, layer_name: str, img: np.ndarray, seg_layers: bool = False + self, layer: ImageLayer, img: np.ndarray, seg_layers: bool = False ) -> None: - self.threshold_inserted[f"[threshold] {layer_name}"] = img + self.threshold_inserted[f"[threshold] {layer.name}"] = img def get_layers_nonthreshold(self) -> list[Layer]: return [ @@ -138,7 +138,7 @@ def get_source_path(self, layer: Layer) -> Optional[Path]: return None - def get_all_segmentation_labels(self) -> list[Labels]: + def get_all_segmentation_labels(self) -> list[Layer]: return [ layer for layer in self.get_all_images() diff --git a/src/allencell_ml_segmenter/main/i_viewer.py b/src/allencell_ml_segmenter/main/i_viewer.py index 4b81fe56..8d2f941f 100644 --- a/src/allencell_ml_segmenter/main/i_viewer.py +++ b/src/allencell_ml_segmenter/main/i_viewer.py @@ -107,5 +107,5 @@ def get_source_path(self, layer: Layer) -> Optional[Path]: pass @abstractmethod - def get_all_segmentation_labels(self) -> list[LabelsLayer]: + def get_all_segmentation_labels(self) -> list[Layer]: pass diff --git a/src/allencell_ml_segmenter/prediction/view.py b/src/allencell_ml_segmenter/prediction/view.py index e5a0b448..29eda78d 100644 --- a/src/allencell_ml_segmenter/prediction/view.py +++ b/src/allencell_ml_segmenter/prediction/view.py @@ -202,8 +202,8 @@ def showResults(self) -> None: metadata={ "source_path": data["seg"], "prob_map": self._img_data_extractor.extract_image_data( - data["seg"], dims=True - ), + data["seg"] + ).np_data, }, ) diff --git a/src/allencell_ml_segmenter/thresholding/thresholding_service.py b/src/allencell_ml_segmenter/thresholding/thresholding_service.py index 25da925f..c3728f38 100644 --- a/src/allencell_ml_segmenter/thresholding/thresholding_service.py +++ b/src/allencell_ml_segmenter/thresholding/thresholding_service.py @@ -69,7 +69,7 @@ def _handle_thresholding_error(self, error: Exception) -> None: show_info("Thresholding failed: " + str(error)) def _on_threshold_changed(self, _: Event) -> None: - segmentation_labels: list[LabelsLayer] = ( + segmentation_labels: list[Layer] = ( self._viewer.get_all_segmentation_labels() ) @@ -93,7 +93,7 @@ def thresholding_task() -> np.ndarray: "Layer metadata must be a dictionary containing the 'prob_map' key in order to threshold." ) - return thresh_function(layer.metadata["prob_map"].np_data) + return thresh_function(layer.metadata["prob_map"]) layer_instance: LabelsLayer = layer From f2889fb23f21dbda11f78d0f8f0341772045e213 Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Wed, 29 Jan 2025 14:30:13 -0800 Subject: [PATCH 11/25] black --- .../thresholding/thresholding_view.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/allencell_ml_segmenter/thresholding/thresholding_view.py b/src/allencell_ml_segmenter/thresholding/thresholding_view.py index 6143007c..a93c04e1 100644 --- a/src/allencell_ml_segmenter/thresholding/thresholding_view.py +++ b/src/allencell_ml_segmenter/thresholding/thresholding_view.py @@ -44,8 +44,6 @@ from qtpy.QtCore import Qt - - class ThresholdingView(View, MainWindow): """ View for thresholding @@ -87,10 +85,12 @@ def __init__( layout.addWidget(self._title, alignment=Qt.AlignmentFlag.AlignHCenter) # selecting input image - self._prediction_result_input_widget: PredictionResultListWidget = PredictionResultListWidget( - self._file_input_model, - self._viewer, - self._input_files_service, + self._prediction_result_input_widget: PredictionResultListWidget = ( + PredictionResultListWidget( + self._file_input_model, + self._viewer, + self._input_files_service, + ) ) self._prediction_result_input_widget.setObjectName("fileInput") layout.addWidget(self._prediction_result_input_widget) From 7586d8a245e89d5f408ce2718adc65a8480d213c Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Thu, 30 Jan 2025 11:15:31 -0800 Subject: [PATCH 12/25] maintain previous selections --- .../core/prediction_result_input_widget.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py index 96111318..31ae4d6f 100644 --- a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py +++ b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py @@ -24,13 +24,16 @@ def __init__( self._prediction_layers: list[LabelsLayer] = [] def _update_layer_list(self) -> None: + previous_selections: list[int] = self._image_list.get_checked_rows() self._image_list.clear() self._prediction_layers = self._viewer.get_all_segmentation_labels() - for prediction_output_layer in self._prediction_layers: + for idx, prediction_output_layer in enumerate(self._prediction_layers): self._image_list.add_item( prediction_output_layer.name, + set_checked=idx in previous_selections ) + def process_checked_signal(self, row: int, state: Qt.CheckState) -> None: if self._model.get_input_mode() == InputMode.FROM_NAPARI_LAYERS: selected_indices: list[int] = self._image_list.get_checked_rows() From a25cf4af4e2a20878925231e5d3e7953fb3aef5c Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Thu, 30 Jan 2025 11:24:24 -0800 Subject: [PATCH 13/25] instance not working correctly --- .../thresholding/thresholding_service.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/allencell_ml_segmenter/thresholding/thresholding_service.py b/src/allencell_ml_segmenter/thresholding/thresholding_service.py index c3728f38..bf6ad064 100644 --- a/src/allencell_ml_segmenter/thresholding/thresholding_service.py +++ b/src/allencell_ml_segmenter/thresholding/thresholding_service.py @@ -99,9 +99,10 @@ def thresholding_task() -> np.ndarray: def on_return( threshold_output: np.ndarray, + layer_to_change: LabelsLayer = layer_instance, ) -> None: self._viewer.insert_threshold( - layer_instance, + layer_to_change, threshold_output, self._main_model.are_predictions_in_viewer(), ) From a598a8831b056e8dfa05a47ffab1e3147ebf4dc9 Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Thu, 30 Jan 2025 12:32:42 -0800 Subject: [PATCH 14/25] threshold only selected layers --- .../thresholding/thresholding_service.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/allencell_ml_segmenter/thresholding/thresholding_service.py b/src/allencell_ml_segmenter/thresholding/thresholding_service.py index bf6ad064..100f5742 100644 --- a/src/allencell_ml_segmenter/thresholding/thresholding_service.py +++ b/src/allencell_ml_segmenter/thresholding/thresholding_service.py @@ -80,7 +80,8 @@ def _on_threshold_changed(self, _: Event) -> None: ) else: thresh_function = self._threshold_image - for layer in segmentation_labels: + for path_layer_to_threshold in self._file_input_model.get_selected_paths(): + layer: Layer = [x for x in segmentation_labels if x.metadata["source_path"] == path_layer_to_threshold][0] # Creating helper functions for mypy strict typing def thresholding_task() -> np.ndarray: # INVARIANT: a segmentation layer must have prob_map in its metadata if it came from our plugin From c22520e55a816f969dfde687ad90b24fd56e3922 Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Thu, 30 Jan 2025 12:38:55 -0800 Subject: [PATCH 15/25] revert --- .../thresholding/thresholding_service.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/allencell_ml_segmenter/thresholding/thresholding_service.py b/src/allencell_ml_segmenter/thresholding/thresholding_service.py index 100f5742..bf6ad064 100644 --- a/src/allencell_ml_segmenter/thresholding/thresholding_service.py +++ b/src/allencell_ml_segmenter/thresholding/thresholding_service.py @@ -80,8 +80,7 @@ def _on_threshold_changed(self, _: Event) -> None: ) else: thresh_function = self._threshold_image - for path_layer_to_threshold in self._file_input_model.get_selected_paths(): - layer: Layer = [x for x in segmentation_labels if x.metadata["source_path"] == path_layer_to_threshold][0] + for layer in segmentation_labels: # Creating helper functions for mypy strict typing def thresholding_task() -> np.ndarray: # INVARIANT: a segmentation layer must have prob_map in its metadata if it came from our plugin From 63cc3132cffe6dd0d46e58fdf52142af066413bb Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Thu, 30 Jan 2025 13:08:19 -0800 Subject: [PATCH 16/25] only threshold selected idx --- .../core/file_input_model.py | 7 +++ .../core/prediction_result_input_widget.py | 8 +-- .../thresholding/thresholding_service.py | 59 +++++++++---------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/allencell_ml_segmenter/core/file_input_model.py b/src/allencell_ml_segmenter/core/file_input_model.py index c0cef960..a1293bb5 100644 --- a/src/allencell_ml_segmenter/core/file_input_model.py +++ b/src/allencell_ml_segmenter/core/file_input_model.py @@ -24,6 +24,7 @@ def __init__(self) -> None: self._input_mode: Optional[InputMode] = None self._selected_paths: Optional[list[Path]] = None self._max_channels: Optional[int] = None + self._selected_idx: Optional[list[int]] = None def get_output_seg_directory(self) -> Optional[Path]: """ @@ -92,3 +93,9 @@ def get_input_files_as_list(self) -> List[Path]: if selected_paths is not None: return selected_paths return [] + + def set_selected_idx(self, selected_idx: list[int]) -> None: + self._selected_idx = selected_idx + + def get_selected_idx(self) -> Optional[list[int]]: + return self._selected_idx diff --git a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py index 31ae4d6f..d6fd25f1 100644 --- a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py +++ b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py @@ -36,10 +36,4 @@ def _update_layer_list(self) -> None: def process_checked_signal(self, row: int, state: Qt.CheckState) -> None: if self._model.get_input_mode() == InputMode.FROM_NAPARI_LAYERS: - selected_indices: list[int] = self._image_list.get_checked_rows() - if state == Qt.CheckState.Checked: - # paths of images to be segmented, which will not be opened again because already in memory - # but satisfies file_input_model state which determines if we have anything selected - self._model.set_selected_paths( - [x.path for x in self._prediction_layers] - ) + self._model.set_selected_idx(self._image_list.get_checked_rows()) diff --git a/src/allencell_ml_segmenter/thresholding/thresholding_service.py b/src/allencell_ml_segmenter/thresholding/thresholding_service.py index bf6ad064..d100383c 100644 --- a/src/allencell_ml_segmenter/thresholding/thresholding_service.py +++ b/src/allencell_ml_segmenter/thresholding/thresholding_service.py @@ -80,40 +80,39 @@ def _on_threshold_changed(self, _: Event) -> None: ) else: thresh_function = self._threshold_image - for layer in segmentation_labels: - # Creating helper functions for mypy strict typing - def thresholding_task() -> np.ndarray: - # INVARIANT: a segmentation layer must have prob_map in its metadata if it came from our plugin - # so we are only supporting thresholding images that are from the plugin itself. - if ( - not isinstance(layer.metadata, dict) - or "prob_map" not in layer.metadata - ): - raise ValueError( - "Layer metadata must be a dictionary containing the 'prob_map' key in order to threshold." + for idx, layer in enumerate(segmentation_labels): + if idx in self._file_input_model.get_selected_idx(): + # Creating helper functions for mypy strict typing + def thresholding_task() -> np.ndarray: + # INVARIANT: a segmentation layer must have prob_map in its metadata if it came from our plugin + # so we are only supporting thresholding images that are from the plugin itself. + if ( + not isinstance(layer.metadata, dict) + or "prob_map" not in layer.metadata + ): + raise ValueError( + "Layer metadata must be a dictionary containing the 'prob_map' key in order to threshold." + ) + + return thresh_function(layer.metadata["prob_map"]) + + def on_return( + threshold_output: np.ndarray, + layer_to_change: LabelsLayer = layer, + ) -> None: + self._viewer.insert_threshold( + layer_to_change, + threshold_output, + self._main_model.are_predictions_in_viewer(), ) - return thresh_function(layer.metadata["prob_map"]) - - layer_instance: LabelsLayer = layer - - def on_return( - threshold_output: np.ndarray, - layer_to_change: LabelsLayer = layer_instance, - ) -> None: - self._viewer.insert_threshold( - layer_to_change, - threshold_output, - self._main_model.are_predictions_in_viewer(), + self._task_executor.exec( + task=thresholding_task, + # lambda functions capture variables by reference so need to pass layer as a default argument + on_return=on_return, + on_error=self._handle_thresholding_error, ) - self._task_executor.exec( - task=thresholding_task, - # lambda functions capture variables by reference so need to pass layer as a default argument - on_return=on_return, - on_error=self._handle_thresholding_error, - ) - def _save_thresholded_images(self, _: Event) -> None: images_to_threshold: list[Path] = ( self._file_input_model.get_input_files_as_list() From e935624d57e791b05867923e393a459ae4d15056 Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Thu, 30 Jan 2025 13:18:06 -0800 Subject: [PATCH 17/25] rename process checked singal function --- .../core/prediction_result_input_widget.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py index d6fd25f1..9dd80bcd 100644 --- a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py +++ b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py @@ -34,6 +34,6 @@ def _update_layer_list(self) -> None: ) - def process_checked_signal(self, row: int, state: Qt.CheckState) -> None: + def _process_checked_signal(self, row: int, state: Qt.CheckState) -> None: if self._model.get_input_mode() == InputMode.FROM_NAPARI_LAYERS: self._model.set_selected_idx(self._image_list.get_checked_rows()) From 148fa75f4283fa416272245e7c4689517fbb0fb1 Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Thu, 30 Jan 2025 13:20:29 -0800 Subject: [PATCH 18/25] lint --- .../core/prediction_result_input_widget.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py index 9dd80bcd..e846f15e 100644 --- a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py +++ b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py @@ -30,10 +30,9 @@ def _update_layer_list(self) -> None: for idx, prediction_output_layer in enumerate(self._prediction_layers): self._image_list.add_item( prediction_output_layer.name, - set_checked=idx in previous_selections + set_checked=idx in previous_selections, ) - def _process_checked_signal(self, row: int, state: Qt.CheckState) -> None: if self._model.get_input_mode() == InputMode.FROM_NAPARI_LAYERS: self._model.set_selected_idx(self._image_list.get_checked_rows()) From fe7d42cc487773e290ac8734fdb408972c1e1fe6 Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Thu, 30 Jan 2025 13:29:48 -0800 Subject: [PATCH 19/25] use the correct layer instance --- .../thresholding/test_thresholding_service.py | 4 +++- .../thresholding/thresholding_service.py | 14 ++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/allencell_ml_segmenter/_tests/thresholding/test_thresholding_service.py b/src/allencell_ml_segmenter/_tests/thresholding/test_thresholding_service.py index fff60bda..5cae4f15 100644 --- a/src/allencell_ml_segmenter/_tests/thresholding/test_thresholding_service.py +++ b/src/allencell_ml_segmenter/_tests/thresholding/test_thresholding_service.py @@ -60,10 +60,11 @@ def test_on_threshold_changed_non_prediction(test_image): viewer: FakeViewer = FakeViewer() main_model: MainModel = MainModel() main_model.set_predictions_in_viewer(True) + file_input_model: FileInputModel = FileInputModel() thresholding_service: ThresholdingService = ThresholdingService( thresholding_model, FakeExperimentsModel(), - FileInputModel(), + file_input_model, main_model, viewer, task_executor=SynchroTaskExecutor.global_instance(), @@ -83,6 +84,7 @@ def test_on_threshold_changed_non_prediction(test_image): metadata={"prob_map": test_image}, ) viewer.add_image(test_image, name="donotthreshold") + file_input_model.set_selected_idx([0, 1]) # ACT set a threshold to trigger thresholding_model.set_thresholding_value(50) diff --git a/src/allencell_ml_segmenter/thresholding/thresholding_service.py b/src/allencell_ml_segmenter/thresholding/thresholding_service.py index d100383c..48a8601c 100644 --- a/src/allencell_ml_segmenter/thresholding/thresholding_service.py +++ b/src/allencell_ml_segmenter/thresholding/thresholding_service.py @@ -83,25 +83,27 @@ def _on_threshold_changed(self, _: Event) -> None: for idx, layer in enumerate(segmentation_labels): if idx in self._file_input_model.get_selected_idx(): # Creating helper functions for mypy strict typing - def thresholding_task() -> np.ndarray: + def thresholding_task( + layer_instance: Layer = layer, + ) -> np.ndarray: # INVARIANT: a segmentation layer must have prob_map in its metadata if it came from our plugin # so we are only supporting thresholding images that are from the plugin itself. if ( - not isinstance(layer.metadata, dict) - or "prob_map" not in layer.metadata + not isinstance(layer_instance.metadata, dict) + or "prob_map" not in layer_instance.metadata ): raise ValueError( "Layer metadata must be a dictionary containing the 'prob_map' key in order to threshold." ) - return thresh_function(layer.metadata["prob_map"]) + return thresh_function(layer_instance.metadata["prob_map"]) def on_return( threshold_output: np.ndarray, - layer_to_change: LabelsLayer = layer, + layer_instance: Layer = layer, ) -> None: self._viewer.insert_threshold( - layer_to_change, + layer_instance, threshold_output, self._main_model.are_predictions_in_viewer(), ) From c56c3023d5f31fa721afc1270b6116d91128c0f8 Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Thu, 30 Jan 2025 14:44:37 -0800 Subject: [PATCH 20/25] working --- .../core/prediction_result_input_widget.py | 6 +++++- .../thresholding/thresholding_service.py | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py index e846f15e..9aebb435 100644 --- a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py +++ b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py @@ -1,3 +1,5 @@ +from typing import Any + from allencell_ml_segmenter.core.file_input_model import ( InputMode, FileInputModel, @@ -9,6 +11,8 @@ from allencell_ml_segmenter.prediction.service import ModelFileService +from napari.utils.events import Event as NapariEvent # type: ignore + class PredictionResultListWidget(FileInputWidget): """ @@ -23,7 +27,7 @@ def __init__( ) self._prediction_layers: list[LabelsLayer] = [] - def _update_layer_list(self) -> None: + def _update_layer_list(self, event: NapariEvent | None = None) -> None: previous_selections: list[int] = self._image_list.get_checked_rows() self._image_list.clear() self._prediction_layers = self._viewer.get_all_segmentation_labels() diff --git a/src/allencell_ml_segmenter/thresholding/thresholding_service.py b/src/allencell_ml_segmenter/thresholding/thresholding_service.py index 48a8601c..73417818 100644 --- a/src/allencell_ml_segmenter/thresholding/thresholding_service.py +++ b/src/allencell_ml_segmenter/thresholding/thresholding_service.py @@ -81,7 +81,10 @@ def _on_threshold_changed(self, _: Event) -> None: else: thresh_function = self._threshold_image for idx, layer in enumerate(segmentation_labels): - if idx in self._file_input_model.get_selected_idx(): + selected_idx: list[int] | None = ( + self._file_input_model.get_selected_idx() + ) + if selected_idx is not None and idx in selected_idx: # Creating helper functions for mypy strict typing def thresholding_task( layer_instance: Layer = layer, From 80eaf0f4d15a3454cfc506e130c6c49c96d35dfc Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Thu, 30 Jan 2025 14:50:39 -0800 Subject: [PATCH 21/25] optional instead of none --- .../core/prediction_result_input_widget.py | 4 ++-- .../thresholding/thresholding_service.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py index 9aebb435..b18f7276 100644 --- a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py +++ b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, Optional from allencell_ml_segmenter.core.file_input_model import ( InputMode, @@ -27,7 +27,7 @@ def __init__( ) self._prediction_layers: list[LabelsLayer] = [] - def _update_layer_list(self, event: NapariEvent | None = None) -> None: + def _update_layer_list(self, event: Optional[NapariEvent] = None) -> None: previous_selections: list[int] = self._image_list.get_checked_rows() self._image_list.clear() self._prediction_layers = self._viewer.get_all_segmentation_labels() diff --git a/src/allencell_ml_segmenter/thresholding/thresholding_service.py b/src/allencell_ml_segmenter/thresholding/thresholding_service.py index 73417818..1335a577 100644 --- a/src/allencell_ml_segmenter/thresholding/thresholding_service.py +++ b/src/allencell_ml_segmenter/thresholding/thresholding_service.py @@ -81,7 +81,7 @@ def _on_threshold_changed(self, _: Event) -> None: else: thresh_function = self._threshold_image for idx, layer in enumerate(segmentation_labels): - selected_idx: list[int] | None = ( + selected_idx: Optional[list[int]] = ( self._file_input_model.get_selected_idx() ) if selected_idx is not None and idx in selected_idx: From dec344ee8c3a2ca4c44aca7fe8cf0e6f23deb3c3 Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Thu, 30 Jan 2025 15:14:36 -0800 Subject: [PATCH 22/25] changing function and varible names to use binary map/prob map --- .../_tests/fakes/fake_viewer.py | 4 +-- .../core/prediction_result_input_widget.py | 4 ++- src/allencell_ml_segmenter/main/i_viewer.py | 4 +-- src/allencell_ml_segmenter/main/viewer.py | 4 +-- .../thresholding/thresholding_service.py | 26 +++++++++++-------- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/allencell_ml_segmenter/_tests/fakes/fake_viewer.py b/src/allencell_ml_segmenter/_tests/fakes/fake_viewer.py index 8797825a..5aa4b95b 100644 --- a/src/allencell_ml_segmenter/_tests/fakes/fake_viewer.py +++ b/src/allencell_ml_segmenter/_tests/fakes/fake_viewer.py @@ -118,7 +118,7 @@ def get_seg_layers(self) -> list[Layer]: if layer.name.startswith("[seg]") ] - def insert_threshold( + def insert_binary_map_into_layer( self, layer: ImageLayer, img: np.ndarray, seg_layers: bool = False ) -> None: self.threshold_inserted[f"[threshold] {layer.name}"] = img @@ -138,7 +138,7 @@ def get_source_path(self, layer: Layer) -> Optional[Path]: return None - def get_all_segmentation_labels(self) -> list[Layer]: + def get_all_layers_containing_prob_map(self) -> list[Layer]: return [ layer for layer in self.get_all_images() diff --git a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py index b18f7276..d4a44fa0 100644 --- a/src/allencell_ml_segmenter/core/prediction_result_input_widget.py +++ b/src/allencell_ml_segmenter/core/prediction_result_input_widget.py @@ -30,7 +30,9 @@ def __init__( def _update_layer_list(self, event: Optional[NapariEvent] = None) -> None: previous_selections: list[int] = self._image_list.get_checked_rows() self._image_list.clear() - self._prediction_layers = self._viewer.get_all_segmentation_labels() + self._prediction_layers = ( + self._viewer.get_all_layers_containing_prob_map() + ) for idx, prediction_output_layer in enumerate(self._prediction_layers): self._image_list.add_item( prediction_output_layer.name, diff --git a/src/allencell_ml_segmenter/main/i_viewer.py b/src/allencell_ml_segmenter/main/i_viewer.py index 8d2f941f..9762677b 100644 --- a/src/allencell_ml_segmenter/main/i_viewer.py +++ b/src/allencell_ml_segmenter/main/i_viewer.py @@ -83,7 +83,7 @@ def get_seg_layers(self) -> list[Layer]: pass @abstractmethod - def insert_threshold( + def insert_binary_map_into_layer( self, layer_name: str, img: np.ndarray, seg_layers: bool = False ) -> None: """ @@ -107,5 +107,5 @@ def get_source_path(self, layer: Layer) -> Optional[Path]: pass @abstractmethod - def get_all_segmentation_labels(self) -> list[Layer]: + def get_all_layers_containing_prob_map(self) -> list[Layer]: pass diff --git a/src/allencell_ml_segmenter/main/viewer.py b/src/allencell_ml_segmenter/main/viewer.py index 48f4ae22..988ff8d7 100644 --- a/src/allencell_ml_segmenter/main/viewer.py +++ b/src/allencell_ml_segmenter/main/viewer.py @@ -141,7 +141,7 @@ def get_seg_layers(self) -> list[Layer]: if layer.name.startswith("[seg]") ] - def insert_threshold( + def insert_binary_map_into_layer( self, layer: Layer, image: np.ndarray, @@ -176,7 +176,7 @@ def get_source_path(self, layer: Layer) -> Optional[Path]: return Path(layer.metadata["source_path"]) return None - def get_all_segmentation_labels(self) -> list[Layer]: + def get_all_layers_containing_prob_map(self) -> list[Layer]: """ Get all segmentation labels layers that currently exist in the viewer. """ diff --git a/src/allencell_ml_segmenter/thresholding/thresholding_service.py b/src/allencell_ml_segmenter/thresholding/thresholding_service.py index 1335a577..df68df44 100644 --- a/src/allencell_ml_segmenter/thresholding/thresholding_service.py +++ b/src/allencell_ml_segmenter/thresholding/thresholding_service.py @@ -69,8 +69,8 @@ def _handle_thresholding_error(self, error: Exception) -> None: show_info("Thresholding failed: " + str(error)) def _on_threshold_changed(self, _: Event) -> None: - segmentation_labels: list[Layer] = ( - self._viewer.get_all_segmentation_labels() + layers_containing_prob_map: list[Layer] = ( + self._viewer.get_all_layers_containing_prob_map() ) # determine thresholding function to use @@ -80,11 +80,15 @@ def _on_threshold_changed(self, _: Event) -> None: ) else: thresh_function = self._threshold_image - for idx, layer in enumerate(segmentation_labels): - selected_idx: Optional[list[int]] = ( - self._file_input_model.get_selected_idx() - ) - if selected_idx is not None and idx in selected_idx: + + selected_idx: Optional[list[int]] = ( + self._file_input_model.get_selected_idx() + ) + + if selected_idx is not None: + for idx in selected_idx: + layer: Layer = layers_containing_prob_map[idx] + # Creating helper functions for mypy strict typing def thresholding_task( layer_instance: Layer = layer, @@ -98,16 +102,16 @@ def thresholding_task( raise ValueError( "Layer metadata must be a dictionary containing the 'prob_map' key in order to threshold." ) - + # This thresholding task returns a binary map return thresh_function(layer_instance.metadata["prob_map"]) def on_return( - threshold_output: np.ndarray, + resulting_binary_map: np.ndarray, layer_instance: Layer = layer, ) -> None: - self._viewer.insert_threshold( + self._viewer.insert_binary_map_into_layer( layer_instance, - threshold_output, + resulting_binary_map, self._main_model.are_predictions_in_viewer(), ) From e798a8e5ebd183ee9848993b3021ccdb4f1e85da Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Thu, 13 Feb 2025 10:05:12 -0800 Subject: [PATCH 23/25] revert uncesseary line --- .../_tests/thresholding/test_thresholding_service.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/allencell_ml_segmenter/_tests/thresholding/test_thresholding_service.py b/src/allencell_ml_segmenter/_tests/thresholding/test_thresholding_service.py index 5cae4f15..c2cb2dbb 100644 --- a/src/allencell_ml_segmenter/_tests/thresholding/test_thresholding_service.py +++ b/src/allencell_ml_segmenter/_tests/thresholding/test_thresholding_service.py @@ -84,7 +84,6 @@ def test_on_threshold_changed_non_prediction(test_image): metadata={"prob_map": test_image}, ) viewer.add_image(test_image, name="donotthreshold") - file_input_model.set_selected_idx([0, 1]) # ACT set a threshold to trigger thresholding_model.set_thresholding_value(50) From 70283fd6221ef6e2741dbaf3cbd1c68b121d2acb Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Thu, 13 Feb 2025 10:10:10 -0800 Subject: [PATCH 24/25] comment for viewer generalized --- src/allencell_ml_segmenter/main/viewer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/allencell_ml_segmenter/main/viewer.py b/src/allencell_ml_segmenter/main/viewer.py index 988ff8d7..86301d00 100644 --- a/src/allencell_ml_segmenter/main/viewer.py +++ b/src/allencell_ml_segmenter/main/viewer.py @@ -148,9 +148,9 @@ def insert_binary_map_into_layer( remove_seg_layers: bool = False, ) -> None: """ - Insert a thresholded image into the viewer. - If a layer for this thresholded image already exists, the new image will replace the old one and refresh the viewer. - If the layer does not exist, it will be added to the viewer in the correct place (on top of the original segmentation image: + Insert a binary mpa image into the viewer. + If a layer for this binary map image already exists, the new image will replace the old one and refresh the viewer. + If the layer does not exist, it will be added to the viewer in the correct place (on top of the original raw image: index_of_segmentation + 1 in the LayerList) :param layer: layer to replace. From 0b1330bb92464d555952461972ff8f52ff611754 Mon Sep 17 00:00:00 2001 From: "brian.kim" Date: Thu, 13 Feb 2025 10:11:44 -0800 Subject: [PATCH 25/25] we do need this --- .../_tests/thresholding/test_thresholding_service.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/allencell_ml_segmenter/_tests/thresholding/test_thresholding_service.py b/src/allencell_ml_segmenter/_tests/thresholding/test_thresholding_service.py index c2cb2dbb..5cae4f15 100644 --- a/src/allencell_ml_segmenter/_tests/thresholding/test_thresholding_service.py +++ b/src/allencell_ml_segmenter/_tests/thresholding/test_thresholding_service.py @@ -84,6 +84,7 @@ def test_on_threshold_changed_non_prediction(test_image): metadata={"prob_map": test_image}, ) viewer.add_image(test_image, name="donotthreshold") + file_input_model.set_selected_idx([0, 1]) # ACT set a threshold to trigger thresholding_model.set_thresholding_value(50)