Conversation
Add a robust psygnal decompile/reload guard to imswitch to avoid mypyc-compiled psygnal breaking subclassing at runtime, and include a small _test_psygnal.py script to validate behavior. Update frontend positioner controls to pass a speed parameter for faster moves. Add av to project dependencies and set tool.uv to forbid binary psygnal wheels (install from source). Tidy VS Code launch/settings and update the dependency lock (uv.lock) to match the dependency changes.
Persist focus-map UI state (accordion visibility) and add UX/performance and robustness improvements: - frontend: FocusMapDimension - Read/write showManualPoints and showMeasuredPoints from Redux (persisted UI) instead of local state. - Add pagination for measured points (POINTS_PAGE_SIZE=20) with Show More/Collapse controls and per-group visible counts. - Display Z-range chip summarizing min/max Z for each group. - Interpolate Z from preview grid (bilinear) when clicking the heatmap and move Z axis to the interpolated focus height. - frontend: FocusMapSlice - Add ui flags showManualPoints/showMeasuredPoints, actions (setShowManualPoints/setShowMeasuredPoints) and selectors. - frontend: store - Add nested persist config for focusMap to persist only the ui subtree (accordion states) and wrap focusMap reducer with persistReducer. - backend: ExperimentController.py - Detect degenerate (single-FOV / near-zero area) regions and compute/assign a combined global focus map for them to avoid duplicate/sparse maps. - backend: focus_map.py - Deduplicate generated grid points (rounding to 3 decimals) to handle degenerate bounds that would otherwise produce duplicate columns. Rationale: persist UI accordion state across sessions, limit rendering cost for large point lists, provide more accurate stage moves by including interpolated Z, and handle degenerate/single-FOV areas reliably by combining maps and deduplicating grid points.
Introduce a floating Picture-in-Picture live preview and propagate per-point Z support across frontend and backend, plus apply snake/raster ordering at the scan-area level for more efficient stage travel. Frontend: add frontend/src/axon/PictureInPicture.js and integrate PiP toggle into AxonTabComponent; extend PointListEditorComponent, WellSelectorCanvas, CoordinateCalculator, and ExperimentSlice to store/use per-point z (default 0), expose Z input in the point editor, move-stage Z on Goto, and include z in converted point lists. CoordinateCalculator also gains applyAreaLevelScanPattern to order scanAreas by rows (with snake reversal) and ensures z is set on positions. Backend: extend Pydantic models (NeighborPoint, Point, ScanPosition, CenterPosition) to include optional z, include z fields in ExperimentController outputs, ensure illumination is turned off at acquisition start, and update Z-stack handling to support per-point Z origins (compute effective Z positions per point). In experiment_normal_mode, add writer_offset handling for multi-timepoint/multi-tile writer indexing and adjust finalization so per-tile writers and final cleanup are addressed correctly. Purpose: allow per-position Z origins for Z-stacks/autofocus, keep live view accessible while working, and improve tile traversal efficiency for multi-area scans.
Multiple fixes and UI improvements across frontend and imswitch backend: - ChannelsDimension: replace exposure select with numeric input (ms) and change default channel inclusion to false so channels must be explicitly enabled for experiments. - ManualPixelCalibrationTab: add optional backlash compensation pre-move step, update step indices and UI (controls, labels, skip button), and adjust step progression to include the new step. - HoloController: make video stream cards flex-responsive, apply transforms (flip/rotate) to the display container, simplify LiveView wrapper usage, and improve processed image sizing/contain behaviour. - ObjectiveSwitcher: fetch objective status on mount and track objectiveState.currentObjective to update local slot and clear switching spinner reliably. - LiveViewController (backend): convert RGB→BGR right before JPEG encoding in JPEG/MJPEG stream workers so encoded JPEG colours are correct for OpenCV encoders. - picamera2_interface: keep frames in RGB in the pipeline (do not convert to BGR globally) and adjust grayscale conversion accordingly; conversion to BGR is deferred to encoders. - experiment_normal_mode: avoid unnecessary per-point Z moves when equal to initial Z, and restrict focus-map lookups to when fitted maps exist; reorganize fallback logic for global/manual maps. These changes fix JPEG colour issues, improve stream layout and responsiveness, add mechanical backlash compensation to manual calibration, prevent redundant Z moves, and require users to opt-in channels for experiments.
Multiple fixes across UI and controllers: - frontend: remove Objective panel from Axon tab and add a compact ObjectiveSwitcher inline in the Experiment Designer. - ChannelsDimension: update summary to show enabled/total channels, count configured state by enabled channels, and include channelEnabledForExperiment in effect deps. - ExperimentSummary: compute total positions via coordinateCalculator (falls back to pointList), count channels using channelEnabledForExperiment, add well selector to dependencies. - ExperimentController: persist illumination intensities/sources for autofocus, turn off illumination after focus-mapping, and activate/set laser power for autofocus using stored intensity or a safe default. - PixelCalibrationController: prefer ObjectiveController runtime state when resolving current objective name; when updating affine calibration preserve existing rotation/flip and only replace scale, reporting rotation_deg. - experiment_normal_mode: lookup focus-mapped Z before per-point Z moves so mapped Z supersedes static per-point moves; only perform per-point Z move when no focus map present. These changes reduce redundant Z moves, ensure correct illumination during autofocus, improve channel summaries, and preserve calibration orientation when updating scale.
Add support for 10/12/16-bit pixel formats: new pixel-type constants and sets (_MONO_HIGHBIT_FORMATS, _BAYER_HIGHBIT_FORMATS). Track the active pixel format (_activePixelFormat) and prefer higher bit-depth mono formats when initializing monochrome cameras; record chosen format for RGB paths too. Use uint16 buffers for >8-bit mono data and adjust reshape logic accordingly. Improve set_pixel_format to apply and remember requested formats and log failures. In HikCamManager convert SDK exposure (µs) to UI ms and compute previewMaxValue from the active pixel format (returns 4095 for high-bit mono, 255 otherwise) so UI ranges match camera bit depth.
Adds a local 3D viewer for the FRAME model and several UX/logic improvements across the PiP and objective switching flows. Key changes: - Add frontend/public/assets/FRAME_reduced-compressed.glb and frame3d.html — a small three.js viewer with GUI to inspect and translate grouped model parts by numeric name suffixes. - Refactor PictureInPicture: make the PiP draggable by title bar and freely resizable via a bottom-right handle, add default/min sizes, separate drag/resize handlers, improve cursor/user-select handling, and ensure the live view always fills the content area. - Integrate Objective into the experiment designer: add a new ObjectiveDimension component, register DIMENSIONS.OBJECTIVE and UI state in ExperimentUISlice, and add the Objective icon to the DimensionBar. - Objective switching improvements: ObjectiveSwitcher now updates app state immediately after a successful move, refreshes full objective status, and fixes a button slot/color mismatch. - Sync objective runtime state: fetchObjectiveControllerGetStatus now dispatches currentObjective when present to keep UI in sync. - Bugfix: AutofocusController stop endpoint corrected to /stopAutofocus. - ObjectiveSlice initial currentObjective changed to null until first status fetch. These changes improve usability (live preview resizing/positioning, inline objective switching) and reliability by syncing controller status to Redux state.
Introduce a Three.js-based FRAME 3D viewer and a configuration panel; integrate it into the Axon tab and persist viewer state. - Added components: Frame3DViewer (three.js GLTF loader + OrbitControls, live position mapping, visibility) and Frame3DViewerPanel (UI for axis mapping, offsets, scale, invert, visibility toggles, and live position chips). - Integrated Frame3DViewerPanel into AxonTabComponent (new tab label "3D Twin"). - Registered frame3DViewer slice in Redux store and added a nested persist config to remember axisConfig, cameraState, and visibility. Files changed: frontend/src/components/Frame3DViewer.jsx (new), frontend/src/axon/Frame3DViewerPanel.jsx (new), frontend/src/axon/AxonTabComponent.js (modified), frontend/src/state/store.js (modified).
Add multi-chip flashing, CAN assignment and related UI/state changes. - Frontend: extend flash API call to accept chip, eraseFlash and skipDisconnect; add new apiUC2ConfigControllerSendCanAddress endpoint. - UsbFlashWizard: add port & options step (chip type select, erase option, skip-disconnect), VID:PID hints & auto-detection, CAN address assignment step and UI, retry/start-over flows, and wire new API calls; update button labels and wizard flow. - Frame3DViewer: fix stale-closure issues by keeping latest positions/axisConfig refs, apply positions immediately after model load, and consolidate mapping logic; adjust default axisConfig mappings. - Redux slices: usbFlashSlice updated with new options (eraseFlash, chipType, skipDisconnect, canAddress, canBaudRate) and step count; Frame3DViewerSlice comments/axis defaults updated. - Backend (UC2ConfigController): refactor flashing into _do_flash, add VID:PID→chip map and chip-specific flash params, support auto-detection of chip, optional erase_flash and skip_disconnect, improved status emissions and error handling; add sendCanAddress API to assign CAN addresses via serial. These changes enable flashing ESP32/ESP32-S2/S3/C3 variants more reliably, provide auto-detection hints in the UI, and optionally assign CAN bus addresses after flashing.
Avoid scanning the same physical location multiple times by deduplicating pointList in CoordinateCalculator (filters and warns) and by blocking duplicate additions in ExperimentSlice (skip & warn). Also: interrupt focus-map when stopping an experiment (ExperimentDesigner), auto-enable "use manual map" after fitting manual focus-map points (FocusMapDimension), and revamp Z-focus UI to numeric Start/Stop/Step fields with a relative-position hint and a summary of planes/range/step (ZFocusDimension). Default objective UI is enabled (ExperimentUISlice). Finally, adjust 3D viewer axis offsets/inversion and turret offset to better align the model with microscope coordinates (Frame3DViewerSlice).
Frontend: ChannelsDimension and ZFocusDimension now use local string state for numeric inputs (exposure and Z start/stop/step) so users can type partial or negative values without fields snapping to 0. Inputs sync from Redux and commit on blur (and validate before dispatching) to avoid premature parsing. Backend: ExperimentController and ExperimentNormalMode were updated to treat zStack values from the UI as pure relative offsets. The controller no longer adds the current stage Z when building z positions (single-plane uses 0.0 offset). Normal-mode now resolves a single base Z per tile (focus-map > per-point > global initial), computes effective absolute Zs as base + offsets, emits Z moves for single-plane and multi-plane cases, applies per-channel chromatic offsets relative to the plane, and returns to the base Z after a Z-stack. Also removed automatic switch-off of illumination at experiment start. These changes centralize Z handling and prevent incorrect absolute Z calculations across tiles and focus-map/autofocus interactions.
Unindent the call to _switch_off_all_illumination so it runs unconditionally after focus mapping, ensuring the acquisition loop always starts from a clean illumination state. In experiment_normal_mode, treat a per-point z value of 0.0 as equivalent to None (frontend default for missing sub-tile Z), falling back to the recorded initial_z_position so the real stage Z isn't overridden by the placeholder 0.0.
Store and restore experiment start position, improve device I/O and raster stability. Key changes: - ExperimentController: capture full initial XYZ at experiment start; add return_to_initial_position(); wait/settle after setting exposure/gain and discard one stale frame; call return-to-start when stopping/pausing workflows. - experiment_normal_mode: append a workflow step to return stage to initial XYZ on the final timepoint. - LightsheetController: switch to tifffile.TiffWriter(imagej=True) and move buffered frame writes to a background thread (write to OME-Zarr and TIFF there) to avoid blocking main thread; improved TIFF writing and finalization handling. - UC2ConfigController: prefer "merged" firmware when flashing to 0x0 (avoids bootloops), attempt download fallback, and improve serial boot/read logic with better waits, logging, and input buffer handling. - WellSelectorUtils: use integer grid indices for BFS expansion (avoid floating-point key collisions) and compute positions deterministically from indices. - ExperimentDesigner: add beforeunload handler to warn user when an experiment is running or paused. - UsbFlashWizard: add "Flash Another Device" button to restart flashing workflow. These changes reduce risk of leaving the stage in an unintended position, make camera parameter updates more robust, prevent main-thread blocking during large writes, improve firmware flashing safety, and fix raster selection instability.
…c2/imswitch into fix-fixes-from-experiments
Introduce a keep-illumination-on setting across UI, state, controller, and workflow to control when illumination is toggled during acquisitions. UI: add an "Illumination Mode" selector in ChannelsDimension (Auto / Always On / Per-Frame). State: add keepIlluminationOn to ExperimentSlice with setter action. Controller: expose keepIlluminationOn in ParameterValue, resolve effective boolean (auto/on/off) based on active channels, log the resolved mode, and pass keep_illumination_on into the experiment workflow. Engine: ExperimentNormalMode honors keep_illumination_on by optionally turning on all active sources once at start, skipping per-frame on/off toggles, and deferring final turn-off until the end (or per-mode rules). Default remains "auto"; changes are backward-compatible.
…C2/ImSwitch into fix-fixes-from-experiments
There was a problem hiding this comment.
Pull request overview
This PR updates ImSwitch’s acquisition and UI stack to improve scan efficiency/robustness (dedup + Z handling + illumination workflow changes), expands frontend functionality (3D digital-twin viewer, PiP live preview, richer focus-map UI), and enhances device/firmware tooling (USB flashing options + CAN address assignment), alongside a few dependency/config cleanups.
Changes:
- Scan/acquisition logic: per-point Z origins, focus-map Z integration, illumination “keep on” mode, writer indexing for multi-timepoint experiments, and grid/scan-point deduplication.
- Frontend enhancements: 3D Twin viewer with persisted camera/axis mapping, picture-in-picture live preview, improved experiment designer dimensions/summaries, and focus-map UX upgrades.
- Hardware & tooling: Hik camera high-bit pixel formats, lightsheet writer behavior, and expanded UC2 USB flashing + CAN address assignment flow.
Reviewed changes
Copilot reviewed 53 out of 55 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
uv.lock |
Adjusts locked Python deps (aiortc/av versions) and adds av to lock metadata. |
pyproject.toml |
Adds av==13.1.0 and configures uv to install psygnal from source. |
imswitch/imcontrol/view/widgets/__init__.py |
Removes StandaStageWidget export/import. |
imswitch/imcontrol/view/widgets/StandaStageWidget.py |
Removes Standa stage widget implementation. |
imswitch/imcontrol/view/guitools/ViewSetupInfo.py |
Removes StandaStage widget mention from docs list. |
imswitch/imcontrol/view/ImConMainView.py |
Removes StandaStage dock entry. |
imswitch/imcontrol/model/managers/detectors/HikCamManager.py |
Uses hardware exposure units conversion; sets preview max based on pixel format. |
imswitch/imcontrol/model/interfaces/picamera2_interface.py |
Keeps frames in RGB (and updates mono conversion accordingly). |
imswitch/imcontrol/model/interfaces/hikcamera.py |
Adds high-bit pixel format constants, tracks active format, and changes buffer dtype/reshape logic. |
imswitch/imcontrol/model/focus_map.py |
Deduplicates generated focus-map grid points for degenerate bounds. |
imswitch/imcontrol/controller/controllers/experiment_controller/experiment_normal_mode.py |
Adds continuous-illumination option, Z “single source of truth” workflow, writer offsets, and revised finalization behavior. |
imswitch/imcontrol/controller/controllers/UC2ConfigController.py |
Adds chip auto-detect + erase/skip-disconnect flash options and CAN address assignment API. |
imswitch/imcontrol/controller/controllers/StandaStageController.py |
Removes Standa stage controller implementation. |
imswitch/imcontrol/controller/controllers/StandaPositionerController.py |
Removes Standa positioner controller implementation. |
imswitch/imcontrol/controller/controllers/PixelCalibrationController.py |
Objective ID resolution via ObjectiveController; preserves affine rotation/flip when updating manual scale calibration. |
imswitch/imcontrol/controller/controllers/LiveViewController.py |
Converts RGB→BGR before JPEG encoding. |
imswitch/imcontrol/controller/controllers/LightsheetController.py |
Uses tifffile ImageJ stack writing and moves buffered writes to a background thread. |
imswitch/imcontrol/controller/controllers/ExperimentController.py |
Adds per-point/per-position Z fields, illumination mode selection, Z-offset semantics, autofocus illumination activation, and return-to-start behavior. |
imswitch/imcommon/framework/noqt.py |
Adds a more robust psygnal “decompile + reload” guard for pure-Python fallback. |
frontend/src/state/store.js |
Adds persisted Frame3D viewer slice and nested persist config for focus-map UI. |
frontend/src/state/slices/usbFlashSlice.js |
Adds chip/erase/skip-disconnect options and CAN assignment wizard step/state. |
frontend/src/state/slices/ObjectiveSlice.js |
Sets currentObjective initial value to null until first status fetch. |
frontend/src/state/slices/Frame3DViewerSlice.js |
New slice: axis mapping, camera state, visibility toggles (persisted). |
frontend/src/state/slices/FocusMapSlice.js |
Persists accordion expansion states for manual/measured points. |
frontend/src/state/slices/ExperimentUISlice.js |
Adds Objective as an experiment-designer dimension. |
frontend/src/state/slices/ExperimentSlice.js |
Adds illumination mode parameter and point deduplication on creation; stores point z. |
frontend/src/middleware/fetchObjectiveControllerGetStatus.js |
Syncs currentObjective into Redux on status fetch. |
frontend/src/components/UsbFlashWizard.jsx |
Adds chip hints, erase/skip-disconnect options, CAN assignment step, and restart flow. |
frontend/src/components/ObjectiveSwitcher.js |
Updates objective switching logic and adds “Switch + Z” buttons. |
frontend/src/components/HoloController.js |
UI layout adjustments for consistent video panel sizing and transforms. |
frontend/src/components/Frame3DViewer.jsx |
New Three.js GLB viewer that maps stage/turret movement from Redux positions. |
frontend/src/components/FRAMESettings/ManualPixelCalibrationTab.js |
Adds backlash-compensation step and updates stepper flow. |
frontend/src/components/AutofocusController.js |
Fixes stop endpoint path (stopAutofocus). |
frontend/src/backendapi/apiUC2ConfigControllerSendCanAddress.js |
New API wrapper for CAN address assignment. |
frontend/src/backendapi/apiUC2ConfigControllerFlashMasterFirmwareUSB.js |
Extends flash API wrapper with chip/erase/skip-disconnect params. |
frontend/src/axon/experiment-designer/ZFocusDimension.js |
Improves Z-stack inputs (supports negative typing) and clarifies relative offsets. |
frontend/src/axon/experiment-designer/ObjectiveDimension.js |
New experiment-designer panel embedding ObjectiveSwitcher. |
frontend/src/axon/experiment-designer/FocusMapDimension.js |
Persists accordion state, adds measured-point pagination, and enables heatmap Z moves. |
frontend/src/axon/experiment-designer/ExperimentSummary.js |
Counts total positions via coordinate calculator; counts enabled channels correctly. |
frontend/src/axon/experiment-designer/ExperimentDesigner.js |
Adds beforeunload warning and focus-map interrupt on stop. |
frontend/src/axon/experiment-designer/DimensionBar.js |
Adds Objective to the dimension bar config. |
frontend/src/axon/experiment-designer/ChannelsDimension.js |
Uses numeric exposure input and adds illumination “keep on” mode UI. |
frontend/src/axon/WellSelectorUtils.js |
Uses integer grid indices in raster BFS to avoid float-key collisions. |
frontend/src/axon/WellSelectorCanvas.js |
Stores current Z into created scan points. |
frontend/src/axon/PointListEditorComponent.js |
Adds Z editing and optional Z move on “Goto”. |
frontend/src/axon/PictureInPicture.js |
New draggable/resizable PiP overlay for live preview. |
frontend/src/axon/OverviewRegistrationWizard.js |
Adds explicit speed to stage jog moves. |
frontend/src/axon/Frame3DViewerPanel.jsx |
New panel for configuring the 3D viewer (mapping/visibility + live readout). |
frontend/src/axon/CoordinateCalculator.js |
Deduplicates scan areas, adds area-level ordering, and propagates Z through scan model. |
frontend/src/axon/AxonTabComponent.js |
Adds PiP toggle and a “3D Twin” tab/panel. |
frontend/public/assets/frame3d.html |
Adds a standalone reference viewer/debug page for the FRAME GLB. |
_test_psygnal.py |
Adds a local diagnostic script for psygnal compilation state. |
.vscode/settings.json |
Adds Python env/project settings for VS Code. |
.vscode/launch.json |
Removes unused whitespace/config blocks. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| // Switch to a different objective, show spinner until we get update from the socket | ||
| const switchTo = async (slot) => { | ||
| const switchTo = async (slot, skipZ = 0) => { | ||
| try { | ||
| setIsSwitching(true); | ||
| await apiObjectiveControllerMoveToObjective(slot, 0); | ||
| // When the socket update arrives, it should set objectiveState.currentObjective => triggers useEffect above | ||
| await apiObjectiveControllerMoveToObjective(slot, skipZ); | ||
| // Move completed – update slot and clear spinner immediately; no need to wait for |
There was a problem hiding this comment.
skipZ is a boolean in the backend (ObjectiveController.moveToObjective), but switchTo defaults it to 0 and both the "Switch to" and "Switch + Z" buttons pass falsy values. As a result, both buttons currently behave the same (Z adjustment is never skipped). Consider making the default skipZ a boolean and wiring the buttons so "Switch to" uses skipZ=true (no Z focus move) while "Switch + Z" uses skipZ=false (include Z move).
| # Set of pixel types that deliver >8-bit mono data (2 bytes per pixel) | ||
| _MONO_HIGHBIT_FORMATS = { | ||
| PixelType_Gvsp_Mono10, | ||
| PixelType_Gvsp_Mono12, | ||
| PixelType_Gvsp_Mono16, | ||
| PixelType_Gvsp_Mono10_Packed, | ||
| PixelType_Gvsp_Mono12_Packed, | ||
| } |
There was a problem hiding this comment.
_MONO_HIGHBIT_FORMATS includes PixelType_Gvsp_Mono10_Packed / PixelType_Gvsp_Mono12_Packed, but the callback path treats every entry in this set as 2-bytes-per-pixel uint16 and reshapes to (h, w). Packed mono formats are bit-packed (not 16-bit-per-pixel), so this will produce incorrect frames or reshape errors if those formats are ever selected. Either remove packed formats from _MONO_HIGHBIT_FORMATS (if not supported) or add explicit unpack/convert logic for the packed formats before reshaping.
| # Finalize OME writers for this timepoint. | ||
| # Per-tile finalization already handled individual tile writers above. | ||
| # On the last timepoint, do a full cleanup pass (no time_index → finalizes all). | ||
| # On intermediate timepoints, skip this step since tile writers are already finalized. | ||
| is_last_timepoint = (t == n_times - 1) | ||
| if is_last_timepoint: | ||
| workflow_steps.append(WorkflowStep( | ||
| name="Turn off illumination", | ||
| name=f"Finalize all OME writers (final cleanup)", | ||
| step_id=step_id, | ||
| main_func=self.controller.set_laser_power, | ||
| main_params={"power": 0, "channel": illu_source}, | ||
| main_func=self.controller.dummy_main_func, | ||
| main_params={}, | ||
| post_funcs=[self.controller.finalize_current_ome_writer], | ||
| post_params={} # No time_index → finalizes all remaining writers | ||
| )) | ||
| step_id += 1 |
There was a problem hiding this comment.
Finalization currently only calls finalize_current_ome_writer on the last timepoint. In _ome_write_single_tiff mode, a separate writer is created per timepoint (see _setup_ome_writers usage), so intermediate timepoints can leave many writers open until the end of the run, increasing open-file handles and memory usage for long timelapses. Consider finalizing the timepoint writer after each timepoint in single-TIFF mode (e.g. by calling finalize_current_ome_writer(..., time_index=t) or equivalent), and/or remove the unused writer_offset parameter here if it’s not needed.
| print("version:", psygnal.__version__) | ||
| print("SignalInstance type:", type(psygnal.SignalInstance)) | ||
|
|
||
| # Try subclassing | ||
| try: | ||
| class TestSub(psygnal.SignalInstance): pass | ||
| print("Subclassing SignalInstance: OK") | ||
| except TypeError as e: | ||
| print("Subclassing SignalInstance FAILED:", e) | ||
|
|
||
| # Try decompile | ||
| try: | ||
| psygnal.utils.decompile() | ||
| class TestSub2(psygnal.SignalInstance): pass | ||
| print("After decompile, subclassing SignalInstance: OK") | ||
| except Exception as e: | ||
| print("After decompile:", e) | ||
|
|
||
| # Test direct instantiation (composition approach) | ||
| try: | ||
| inst = psygnal.SignalInstance((int,), name="test") | ||
| print("Direct instantiation: OK, name =", inst.name) | ||
| except Exception as e: | ||
| print("Direct instantiation FAILED:", e) |
There was a problem hiding this comment.
This looks like an ad-hoc diagnostic script. Keeping it at repo root makes it easy to ship accidentally and can confuse packaging/test discovery. Consider moving it under a dedicated scripts/ or tools/ directory (or adding it to .gitignore if it’s meant to be local-only), and ensure it’s not picked up by any test runner.
| print("version:", psygnal.__version__) | |
| print("SignalInstance type:", type(psygnal.SignalInstance)) | |
| # Try subclassing | |
| try: | |
| class TestSub(psygnal.SignalInstance): pass | |
| print("Subclassing SignalInstance: OK") | |
| except TypeError as e: | |
| print("Subclassing SignalInstance FAILED:", e) | |
| # Try decompile | |
| try: | |
| psygnal.utils.decompile() | |
| class TestSub2(psygnal.SignalInstance): pass | |
| print("After decompile, subclassing SignalInstance: OK") | |
| except Exception as e: | |
| print("After decompile:", e) | |
| # Test direct instantiation (composition approach) | |
| try: | |
| inst = psygnal.SignalInstance((int,), name="test") | |
| print("Direct instantiation: OK, name =", inst.name) | |
| except Exception as e: | |
| print("Direct instantiation FAILED:", e) | |
| def main() -> None: | |
| print("version:", psygnal.__version__) | |
| print("SignalInstance type:", type(psygnal.SignalInstance)) | |
| # Try subclassing | |
| try: | |
| class TestSub(psygnal.SignalInstance): | |
| pass | |
| print("Subclassing SignalInstance: OK") | |
| except TypeError as e: | |
| print("Subclassing SignalInstance FAILED:", e) | |
| # Try decompile | |
| try: | |
| psygnal.utils.decompile() | |
| class TestSub2(psygnal.SignalInstance): | |
| pass | |
| print("After decompile, subclassing SignalInstance: OK") | |
| except Exception as e: | |
| print("After decompile:", e) | |
| # Test direct instantiation (composition approach) | |
| try: | |
| inst = psygnal.SignalInstance((int,), name="test") | |
| print("Direct instantiation: OK, name =", inst.name) | |
| except Exception as e: | |
| print("Direct instantiation FAILED:", e) | |
| if __name__ == "__main__": | |
| main() |
This pull request introduces several significant enhancements and fixes to the frontend and coordinate calculation logic, focusing on improving scan efficiency, UI features, and robustness. The most important changes include deduplication of scan points, implementation of area-level scan ordering, addition of 3D viewer and picture-in-picture UI components, and improved handling of Z coordinates in scan computations.
Scan coordinate calculation improvements:
experimentState.pointListbefore processing to prevent scanning the same physical location multiple times, improving scan efficiency and avoiding redundant operations.applyAreaLevelScanPattern) to optimize stage movement across multi-area experiments, grouping areas into rows and applying snake/raster ordering as appropriate. [1] [2]Frontend UI enhancements:
Frame3DViewerPanelcomponent for interactive 3D visualization of the microscope model. [1] [2]Codebase and configuration updates:
.vscode/settings.jsonto specify Python project environment and package manager, improving developer workflow..vscode/launch.jsonby removing unused configuration blocks. [1] [2]These changes collectively improve scan accuracy, UI usability, and maintainability of the codebase.