Add channel-aware defocus reference status#1225
Conversation
Display the active defocus reference in the main Channel Settings table so users can see whether the zero-defocus plane is set and which channel/focus position established it. Update the autofocus popup channel selector to use CH labels while preserving channel_n keys internally, and publish captured autofocus references to the main GUI. Publish runtime zero-defocus reference updates from microscope channel preparation and clear the reference when manual focus moves invalidate it. Tests cover autofocus channel label conversion, main-GUI defocus reference updates, and model reference publication/clearing.
Scope the mocked parent_controller.execute with patch.object in the autofocus calibration test so the package-scoped dummy_controller restores its real execute method after the assertion. This fixes the Windows CI order failure where camera view move_stage tests ran after the autofocus test and saw an empty command list because DummyController.execute had been replaced by a MagicMock. Confirmed the failure locally with the autofocus/camera-view ordering reproducer before the fix, then verified the reproducer and the affected controller test files pass in the navigate conda environment.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #1225 +/- ##
===========================================
+ Coverage 64.22% 64.85% +0.62%
===========================================
Files 189 190 +1
Lines 26104 26542 +438
===========================================
+ Hits 16766 17213 +447
+ Misses 9338 9329 -9
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR makes channel defocus values consistently relative to a runtime “zero-defocus” reference plane, exposes the active reference plane in the Channels UI, and adds an autofocus calibration workflow to capture a temporary reference focus and populate per-channel defocus values.
Changes:
- Add runtime
zero_defocus_focustracking inMicroscopeand publish/clear GUI defocus-reference status events. - Update z-stack (software + ASI) focus targeting to compute absolute focus per channel relative to a zero-defocus reference.
- Extend autofocus UI/controller/model flow to select a target channel, capture a reference focus, and populate channel defocus values (plus tests/docs).
Reviewed changes
Copilot reviewed 21 out of 22 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| test/model/test_model.py | Adds regression test ensuring live autofocus injection preserves passed args. |
| test/model/test_microscope.py | Adds tests for deriving and clearing runtime zero-defocus reference in channel prep. |
| test/model/features/test_common_features.py | Adds tests verifying z-stack focus targets use zero-defocus-relative channel defocus. |
| test/model/features/test_autofocus.py | Adds tests for channel-aware autofocus prep and completion payload. |
| test/controller/sub_controllers/test_channels_tab.py | Adds tests for channel defocus widget updates and defocus-reference label updates. |
| test/controller/sub_controllers/test_autofocus.py | Adds tests for capture-reference/populate-defocus controller workflow and label mapping. |
| test/config/test_config.py | Adds test ensuring negative per-channel defocus survives config verification. |
| src/navigate/view/popups/autofocus_setting_popup.py | Adds channel + calibration action selectors and a reference status label. |
| src/navigate/view/main_window_content/channels_tab.py | Adds a “Defocus Reference: …” status label to the Channel Settings table. |
| src/navigate/model/model.py | For live mode, forwards autofocus command args into the injected Autofocus feature spec. |
| src/navigate/model/microscope.py | Implements runtime zero-defocus reference derivation, publication, clearing, and focus restore. |
| src/navigate/model/features/common_features.py | Adds helper to compute focus targets per channel relative to zero-defocus reference; refactors z-stack focus math. |
| src/navigate/model/features/autofocus.py | Extends Autofocus args and emits autofocus_complete payloads for calibration workflows. |
| src/navigate/controller/sub_controllers/channels_tab.py | Adds custom events to set per-channel defocus widgets and the defocus-reference label. |
| src/navigate/controller/sub_controllers/autofocus.py | Adds calibration workflow (capture reference, populate defocus) and channel label/key mapping utilities. |
| src/navigate/config/gui_configuration.yml | Allows negative defocus values in GUI config constraints. |
| src/navigate/config/config.py | Updates experiment verification to allow negative defocus while still rejecting other negative fields. |
| docs/superpowers/plans/2026-06-13-channel-aware-defocus-autofocus-calibration.md | Adds internal implementation plan documentation for the feature set. |
| docs/source/02_user_guide/03_user_interface_walkthrough/06_popups_and_tools.rst | Documents autofocus calibration workflow behavior and persistence. |
| docs/source/02_user_guide/03_user_interface_walkthrough/03_acquisition_and_settings_notebooks.rst | Updates user-facing definition of Defocus to be zero-defocus-relative. |
| docs/source/01_getting_started/06_acquiring_data.rst | Updates getting-started guidance for defocus meaning and usage. |
| .gitignore | Normalizes uv.lock entry and ignores .worktrees/. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Move target-channel preparation out of Autofocus.run() and into the signal init hook so standalone autofocus and live-mode injected autofocus share the same channel-selection behavior. This addresses the PR review concern that live autofocus injection preserves target channel args but bypasses Autofocus.run(), which previously meant prepare_channel() was never called for the injected feature instance. Tests now verify that run() only orchestrates standalone autofocus loading while pre_func_signal() prepares either the requested channel or the next selected channel fallback.
Autofocus stage moves publish a transient defocus_reference=None event through the model, which can clear the main Channel Settings label during Regular and Populate Defocus runs. Capture Reference already republished the saved reference after completion. Extend that restoration to other autofocus completions whenever an autofocus calibration reference exists, so the main GUI label does not remain at Not Set after Populate Defocus or Regular autofocus. Adds regression coverage for Populate Defocus and Regular autofocus completion preserving the saved defocus reference event.
Summary
Defocus Reference: Not SetorDefocus Reference: CHn @ positionCH1,CH2, etc.) while preserving internalchannel_nkeysWhy
Users need a visible main-GUI indication of the reference plane that channel defocus values are relative to. Without this, nonzero defocus values can look absolute or appear tied to whichever channel happens to be selected first.
Validation
conda run -n navigate python -m pytest test/controller/sub_controllers/test_autofocus.py test/controller/sub_controllers/test_channels_tab.py test/model/test_microscope.py -qruff check src/navigate/view/main_window_content/channels_tab.py src/navigate/controller/sub_controllers/channels_tab.py src/navigate/controller/sub_controllers/autofocus.py src/navigate/model/microscope.py test/controller/sub_controllers/test_channels_tab.py test/controller/sub_controllers/test_autofocus.py test/model/test_microscope.py