Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion datalab/adapters_metadata/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def append(self, adapter: BaseResultAdapter, obj: SignalObj | ImageObj) -> None:
if "roi_index" in df.columns:
i_roi = int(df.iloc[i_row_res]["roi_index"])
roititle = ""
if i_roi >= 0 and obj.roi is not None:
if i_roi >= 0 and obj.roi is not None and i_roi < len(obj.roi):
roititle = obj.roi.get_single_roi_title(i_roi)
ylabel += f"|{roititle}"
self.ylabels.append(ylabel)
Expand Down
33 changes: 33 additions & 0 deletions datalab/gui/processor/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,30 @@ def register_computations(self) -> None:
self.register_processing()
self.register_analysis()

# pylint: disable=unused-argument
def preprocess_1_to_0(
self,
func: Callable,
param: gds.DataSet | None,
objs: list[SignalObj | ImageObj],
) -> bool:
"""Pre-check hook for 1-to-0 operations (hook method).

This method is called before a 1-to-0 computation starts, before the
progress dialog is opened. Subclasses can override this method to perform
pre-checks or ask for user confirmation. Return ``False`` to abort the
computation.

Args:
func: The computation function that will be called
param: Optional parameter set
objs: List of objects that will be processed

Returns:
True to proceed with the computation, False to abort
"""
return True

# pylint: disable=unused-argument
def postprocess_1_to_0_result(
self, obj: SignalObj | ImageObj, result: GeometryResult | TableResult
Expand Down Expand Up @@ -989,6 +1013,13 @@ def auto_recompute_analysis(
# Get the parameter from processing parameters
param = proc_params.param

# Disable ROI creation during auto-recompute: detection functions store
# create_rois=True in their parameters, but auto-recompute should only
# update analysis results, not recreate ROIs (which would make them
# impossible to delete or modify).
if hasattr(param, "create_rois"):
param.create_rois = False

# Get the actual function from the function name
feature = self.get_feature(proc_params.func_name)

Expand Down Expand Up @@ -1394,6 +1425,8 @@ def compute_1_to_0(
if target_objs is not None
else self.panel.objview.get_sel_objects(include_groups=True)
)
if not self.preprocess_1_to_0(func, param, objs):
return None
current_obj = self.panel.objview.get_current_object()
title = func.__name__ if title is None else title
refresh_needed = False
Expand Down
46 changes: 46 additions & 0 deletions datalab/gui/processor/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from __future__ import annotations

import guidata.dataset as gds
import numpy as np
import sigima.params
import sigima.proc.base as sipb
Expand All @@ -25,6 +26,7 @@
)
from sigima.objects.scalar import GeometryResult, TableResult

from datalab import env
from datalab.config import APP_NAME, _
from datalab.gui.processor.base import BaseProcessor
from datalab.gui.processor.geometry_postprocess import (
Expand Down Expand Up @@ -55,6 +57,50 @@ def _wrap_geometric_transform(self, func, operation: str):
"""
return GeometricTransformWrapper(func, operation)

def preprocess_1_to_0(
self,
func,
param: gds.DataSet | None,
objs: list[ImageObj],
) -> bool:
"""Override to confirm ROI replacement before the progress bar opens.

When the parameter has ``create_rois=True`` and at least one selected
image already has ROIs, the user is warned that the existing ROIs will
be replaced.

Args:
func: The computation function that will be called
param: Optional parameter set
objs: List of image objects that will be processed

Returns:
True to proceed with the computation, False to abort
"""
if (
param is not None
and getattr(param, "create_rois", False)
and not env.execenv.unattended
and any(obj.roi is not None and not obj.roi.is_empty() for obj in objs)
):
return (
QW.QMessageBox.question(
self.mainwindow,
_("Warning"),
_(
"Regions of interest are already defined for this "
"image.<br><br>"
"Creating new ROIs from detection will replace the "
"existing ones, which will be lost.<br><br>"
"Do you want to continue?"
),
QW.QMessageBox.Yes | QW.QMessageBox.No,
QW.QMessageBox.No,
)
== QW.QMessageBox.Yes
)
return True

def postprocess_1_to_0_result(
self, obj: ImageObj, result: GeometryResult | TableResult
) -> bool:
Expand Down
Loading