Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add MDA progress widget #268

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
25 changes: 20 additions & 5 deletions examples/mda_demo.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import numpy as np
import useq
from pymmcore_plus import CMMCorePlus
from qtpy.QtWidgets import (
QApplication,
Expand Down Expand Up @@ -29,7 +30,7 @@ class MDA(QWidget):
events to print out the current state of the acquisition.
"""

def __init__(self) -> None:
def __init__(self, seq: useq.MDASequence | None = None) -> None:
super().__init__()
# get the CMMCore instance and load the default config
self.mmc = CMMCorePlus.instance()
Expand All @@ -43,6 +44,9 @@ def __init__(self) -> None:

# instantiate the MDAWidget, and a couple labels for feedback
self.mda = MDAWidget()
if seq:
self.mda.setValue(seq)

self.mda.valueChanged.connect(self._update_sequence)
self.current_sequence = QLabel('... enter info and click "Run"')
self.current_event = QLabel("... current event info will appear here")
Expand All @@ -60,7 +64,8 @@ def __init__(self) -> None:

def _update_sequence(self) -> None:
"""Called when the MDA sequence starts."""
self.current_sequence.setText(self.mda.value().yaml(exclude_defaults=True))
mda_seq = self.mda.value()
self.current_sequence.setText(mda_seq.yaml(exclude_defaults=True))

def _on_frame(self, image: np.ndarray, event: MDAEvent) -> None:
"""Called each time a frame is acquired."""
Expand All @@ -84,6 +89,16 @@ def _on_pause(self, state: bool) -> None:

if __name__ == "__main__":
app = QApplication([])
frame = MDA()
frame.show()
app.exec_()

seq = useq.MDASequence(
time_plan=useq.TIntervalLoops(interval=1, loops=4),
z_plan=useq.ZRangeAround(range=2, step=0.5),
channels=[
{"config": "DAPI", "exposure": 10},
{"config": "FITC", "exposure": 20},
],
)
wdg = MDA(seq)
wdg.show()

app.exec()
20 changes: 0 additions & 20 deletions examples/z_plan_widget.py

This file was deleted.

3 changes: 2 additions & 1 deletion src/pymmcore_widgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"InstallWidget",
"LiveButton",
"MDAWidget",
"MDAProgressWidget",
"MDASequenceWidget",
"ObjectivesWidget",
"ObjectivesPixelConfigurationWidget",
Expand Down Expand Up @@ -66,7 +67,7 @@
from .device_properties import PropertiesWidget, PropertyBrowser, PropertyWidget
from .hcs import HCSWizard
from .hcwizard import ConfigWizard
from .mda import MDAWidget
from .mda import MDAProgressWidget, MDAWidget
from .useq_widgets import (
ChannelTable,
GridPlanWidget,
Expand Down
3 changes: 2 additions & 1 deletion src/pymmcore_widgets/mda/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""MDA widgets."""

from ._core_mda import MDAWidget
from ._mda_progress_widget import MDAProgressWidget

__all__ = ["MDAWidget"]
__all__ = ["MDAWidget", "MDAProgressWidget"]
25 changes: 23 additions & 2 deletions src/pymmcore_widgets/mda/_core_mda.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from qtpy.QtCore import QSize, Qt
from qtpy.QtWidgets import (
QBoxLayout,
QFrame,
QHBoxLayout,
QMessageBox,
QPushButton,
Expand All @@ -26,6 +27,7 @@
from ._core_grid import CoreConnectedGridPlanWidget
from ._core_positions import CoreConnectedPositionTable
from ._core_z import CoreConnectedZPlanWidget
from ._mda_progress_widget import MDAProgressBars
from ._save_widget import SaveGroupBox


Expand Down Expand Up @@ -76,6 +78,18 @@ class MDAWidget(MDASequenceWidget):
By default, None. If not specified, the widget will use the active
(or create a new)
[`CMMCorePlus.instance`][pymmcore_plus.core._mmcore_plus.CMMCorePlus.instance].

Attributes
----------
progress_bars : MDAProgressBars
The progress bars widget that shows the progress of the MDA sequence, it
also provides a visual representation of the size of each dimension.
Can be hidden with `self.progress_bars.hide()`.
save_info : SaveGroupBox
The save widget that allows the user to specify the save directory and
file name. Can be hidden with `self.save_info.hide()`.
control_btns : _MDAControlButtons
The run, pause, and cancel buttons at the bottom of the MDA Widget.
"""

def __init__(
Expand All @@ -86,6 +100,9 @@ def __init__(

super().__init__(parent=parent, tab_widget=CoreMDATabs(None, self._mmc))

self.progress_bars = MDAProgressBars()
self.progress_bars.setFrameStyle(QFrame.Shape.Panel | QFrame.Shadow.Raised)

self.save_info = SaveGroupBox(parent=self)
self.save_info.valueChanged.connect(self.valueChanged)
self.control_btns = _MDAControlButtons(self._mmc, self)
Expand All @@ -97,11 +114,11 @@ def __init__(
# ------------ layout ------------

layout = cast("QBoxLayout", self.layout())
layout.insertWidget(0, self.save_info)
layout.insertWidget(0, self.progress_bars)
layout.insertWidget(1, self.save_info)
layout.addWidget(self.control_btns)

# ------------ connect signals ------------

self.control_btns.run_btn.clicked.connect(self.run_mda)
self.control_btns.pause_btn.released.connect(self._mmc.mda.toggle_pause)
self.control_btns.cancel_btn.released.connect(self._mmc.mda.cancel)
Expand Down Expand Up @@ -249,6 +266,10 @@ def run_mda(self) -> None:

# ------------------- private Methods ----------------------

def _on_value_change(self) -> None:
super()._on_value_change()
self.progress_bars.prepare_sequence(self.value())

def _on_sys_config_loaded(self) -> None:
# TODO: connect objective change event to update suggested step
self.z_plan.setSuggestedStep(_guess_NA(self._mmc) or 0.5)
Expand Down
Loading
Loading