Skip to content

Commit

Permalink
Separate napari image parameter to prevent magicgui slowdown (#401)
Browse files Browse the repository at this point in the history
* Separate image parameter to prevent magicgui slowdown.

* Fix parameters not initialized.

* Apply suggestions from code review

Co-authored-by: Igor Tatarnikov <[email protected]>

---------

Co-authored-by: Igor Tatarnikov <[email protected]>
  • Loading branch information
matham and IgorTatarnikov authored Apr 16, 2024
1 parent 152ece5 commit 389e455
Showing 1 changed file with 82 additions and 7 deletions.
89 changes: 82 additions & 7 deletions cellfinder/napari/detect/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,59 @@ def detect_widget() -> FunctionGui:
"""
progress_bar = ProgressBar()

# options that is filled in from the gui
options = {"signal_image": None, "background_image": None, "viewer": None}

# signal and background images are separated out from the main magicgui
# parameter selections and are inserted as widget children in their own
# sub-containers of the root. Because if these image parameters are
# included in the root widget, every time *any* parameter updates, the gui
# freezes for a bit likely because magicgui is processing something for
# all the parameters when any parameter changes. And this processing takes
# particularly long for image parameters. Placing them as sub-containers
# alleviates this
@magicgui(
call_button=False,
persist=False,
scrollable=False,
labels=False,
auto_call=True,
)
def signal_image_opt(
viewer: napari.Viewer,
signal_image: napari.layers.Image,
):
"""
magicgui widget for setting the signal_image parameter.
Parameters
----------
signal_image : napari.layers.Image
Image layer containing the labelled cells
"""
options["signal_image"] = signal_image
options["viewer"] = viewer

@magicgui(
call_button=False,
persist=False,
scrollable=False,
labels=False,
auto_call=True,
)
def background_image_opt(
background_image: napari.layers.Image,
):
"""
magicgui widget for setting the background image parameter.
Parameters
----------
background_image : napari.layers.Image
Image layer without labelled cells
"""
options["background_image"] = background_image

@magicgui(
detection_label=html_label_widget("Cell detection", tag="h3"),
**DataInputs.widget_representation(),
Expand All @@ -52,9 +105,6 @@ def detect_widget() -> FunctionGui:
def widget(
detection_label,
data_options,
viewer: napari.Viewer,
signal_image: napari.layers.Image,
background_image: napari.layers.Image,
voxel_size_z: float,
voxel_size_y: float,
voxel_size_x: float,
Expand Down Expand Up @@ -83,10 +133,6 @@ def widget(
Parameters
----------
signal_image : napari.layers.Image
Image layer containing the labelled cells
background_image : napari.layers.Image
Image layer without labelled cells
voxel_size_z : float
Size of your voxels in the axial dimension
voxel_size_y : float
Expand Down Expand Up @@ -129,9 +175,24 @@ def widget(
reset_button :
Reset parameters to default
"""
# we must manually call so that the parameters of these functions are
# initialized and updated. Because, if the images are open in napari
# before we open cellfinder, then these functions may never be called,
# even though the image filenames are shown properly in the parameters
# in the gui. Likely auto_call doesn't make magicgui call the functions
# in this circumstance, only if the parameters are updated once
# cellfinder plugin is fully open and initialized
signal_image_opt()
background_image_opt()

signal_image = options["signal_image"]
background_image = options["background_image"]
viewer = options["viewer"]

if signal_image is None or background_image is None:
show_info("Both signal and background images must be specified.")
return

data_inputs = DataInputs(
signal_image.data,
background_image.data,
Expand Down Expand Up @@ -222,6 +283,20 @@ def restore_defaults():
# Insert progress bar before the run and reset buttons
widget.insert(-3, progress_bar)

# add the signal and background image parameters
# make it look as if it's directly in the root container
signal_image_opt.margins = 0, 0, 0, 0
# the parameters are updated using `auto_call` only. If False, magicgui
# passes these as args to widget(), which doesn't list them as args
signal_image_opt.gui_only = True
widget.insert(3, signal_image_opt)
widget.signal_image_opt.label = "Signal image"

background_image_opt.margins = 0, 0, 0, 0
background_image_opt.gui_only = True
widget.insert(4, background_image_opt)
widget.background_image_opt.label = "Background image"

scroll = QScrollArea()
scroll.setWidget(widget._widget._qwidget)
widget._widget._qwidget = scroll
Expand Down

0 comments on commit 389e455

Please sign in to comment.