acia.notebook#

Jupyter notebook visualization mixin for image sequence sources.

acia.notebook.normalize_to_uint8(image_array)[source]#

Normalize an image array to the uint8 [0, 255] range.

A uint8 array is passed through unchanged; any other dtype is min-max scaled to [0, 255]. A flat array (max == min) maps to all zeros.

Parameters:

image_array (ndarray) – Source image array of any dtype/shape.

Returns:

np.ndarray – A uint8 array of the same shape.

Return type:

ndarray

class acia.notebook.JupyterVisualizationMixin[source]#

Bases: object

Mixin providing interactive Jupyter notebook visualization for image sequences.

This mixin expects the host class to implement the ImageSequenceSource interface with these properties/methods: - size_t: int - number of time frames - num_channels: int - number of channels - get_frame(frame: int) -> BaseImage

Example usage:
class MyImageSource(ImageSequenceSource, JupyterVisualizationMixin):

get_frame(frame)[source]#

Get frame at given index.

Parameters:

frame (int)

Return type:

BaseImage

class acia.notebook.ROICropper[source]#

Bases: AnyWidget

Interactive rotated-rectangle ROI selector over frame 0 (anywidget).

Draw/drag/resize/rotate a rectangle over the first frame of an ImageSequenceSource and emit a RotatedCropSpec. Two ways to set the box, both feeding the same synced traits:

  1. Click >=3 points around the ROI (the points trait); an observer runs fit_to_points() (cv2.minAreaRect) to seed the tightest oriented rectangle. The geometry lives in Python, so it is unit-tested.

  2. Drag the box / corner handles / rotate knob in the ESM render().

ROI coordinates are kept in parent image pixels so spec plugs straight into crop_rotated().

Works in Jupyter/Colab and in marimo via mo.ui.anywidget(cropper) (it IS-A ipywidgets DOMWidget). The ESM JavaScript is best-effort and is verified only by a real notebook run, not by the headless test-suite.

center_x#

A float trait.

center_y#

A float trait.

width#

An integer trait.

height#

An integer trait.

angle#

A float trait.

points#

An instance of a Python list.

image_b64#

A trait for unicode strings.

image_w#

An integer trait.

image_h#

An integer trait.

__init__(source, *, width=None, height=None, channel=None, **kwargs)[source]#

Build the widget from a source’s frame 0.

Parameters:
  • source – The ImageSequenceSource to crop.

  • width (int | None) – Default ROI width (px). Defaults to frame_w // 2.

  • height (int | None) – Default ROI height (px). Defaults to frame_h // 2.

  • channel (int | None) – Display channel for a multi-channel frame. Defaults to channel 0.

  • **kwargs – Forwarded to anywidget.AnyWidget.

Return type:

None

fit_to_points(points=None)[source]#

Fit the tightest oriented rectangle to points and set traits.

Uses cv2.minAreaRect on the given (or the points trait’s) [x, y] image-px points, then normalizes the angle into (-45, 45] degrees (CCW, OpenCV getRotationMatrix2D / RotatedCropSpec convention), swapping width and height with each 90-degree step so the round-trip fit_to_points -> crop_rotated straightens the region. Sizes are rounded to positive ints.

Parameters:

points[[x, y], ...] image-px points. Defaults to the current points trait when None.

Raises:

ValueError – If fewer than 3 points are supplied, or if the points are collinear/duplicate (degenerate rectangle).

property spec#

Return the current ROI as a RotatedCropSpec.

cropped()[source]#

Return source.crop_rotated(self.spec) (a lazy crop source).

save(dataset_dir, **kwargs)[source]#

Persist the crop via save_crop_capture().

Parameters:
  • dataset_dir – Directory the capture is written to.

  • **kwargs – Forwarded to save_crop_capture (frame, channel, clip_percentiles, source_ref).

Returns:

dict – The save_crop_capture result.

class acia.notebook.FilterExplorer[source]#

Bases: AnyWidget

Interactive cell-filter threshold explorer with live mask preview.

Auto-builds one (min, max) slider per filter from the passed filters list (modular – add a CellFilter and it appears) and live-recolours the contour overlay (kept = green, dropped = red) as the handles move. The live filtering runs entirely client-side: each contour’s value under each filter is precomputed once in Python (reusing the goal-E value() calibration) and shipped to the browser, so dragging a slider needs no kernel round-trip (the workflow’s “reactive, no observer wiring”). All control ranges/handles are in each filter’s physical unit (µm, µm², dimensionless).

The widget previews a single frame (frame=0 by default), drawing only that frame’s contours over that frame’s image. params and configured_filters() emit/restore frame-independent thresholds; filtered_overlay() applies them across the whole overlay via apply_cell_filters().

Works in Jupyter/Colab and in marimo via mo.ui.anywidget(explorer). The ESM JavaScript is best-effort, verified by the headless Playwright suite (and a real notebook run), not by the pure-Python tests.

image_b64#

A trait for unicode strings.

image_w#

An integer trait.

image_h#

An integer trait.

filter_specs#

An instance of a Python list.

contours#

An instance of a Python list.

selection#

An instance of a Python list.

__init__(overlay, images, filters, properties, *, frame=0, channel=None, **kwargs)[source]#

Build the explorer from an overlay, a calibrated source and filters.

Parameters:
  • overlay – The Overlay to filter.

  • images – The calibrated ImageSequenceSource (must expose a non-None pixel_size).

  • filters – A list of CellFilter instances – one slider control is built per filter.

  • properties – The extractor table for overlay (see execute()). Each filter’s slider is seeded from its own column, so it must contain a column named after every filter passed in.

  • frame (int) – Frame to preview (image + its contours). Defaults to 0.

  • channel (int | None) – Display channel for a multi-channel frame. Defaults to 0.

  • **kwargs – Forwarded to anywidget.AnyWidget.

Raises:

ValueError – If images is None or its pixel_size is None (physical-unit thresholds need calibration).

Return type:

None

property params#

Current thresholds as [{name, vmin, vmax}] pint Quantitys.

A handle parked at its track extreme is reported as None (open on that side), so a one-sided filter round-trips faithfully.

configured_filters()[source]#

Update each passed filter’s vmin/vmax from the sliders.

Mutates the filter instances supplied to __init__ in place (a handle at its extreme sets that bound to None) and returns the list, ready for apply_cell_filters() or the scaled batch run.

filtered_overlay()[source]#

Return the whole overlay filtered by the current thresholds.

save(path)[source]#

Write the current thresholds to path as filter_params.json.

Serializes [{name, unit, vmin, vmax}] (magnitudes; None for an open side) – a small spec the scaled batch run reloads to rebuild the filters.

Parameters:

path – Destination JSON file path.

Returns:

list[dict] – The serialized filter parameters.

class acia.notebook.SequenceDashboard[source]#

Bases: AnyWidget

Curate positions + ROIs across a multi-position acquisition (anywidget).

A three-pane UI (position gallery / ROI editor / selection list) over a SequenceFile. Browse positions, mark ROIs (draw or point-fit), and emit a SelectionManifest. Frames are read lazily from the source and pushed to the browser as PNG bytes; the widget never loads the whole (possibly hundreds-of-GB) file.

Works in Jupyter/Colab and in marimo via mo.ui.anywidget(dash). The ESM is best-effort and verified only by a real notebook run (or the Playwright suite in the devcontainer), not by the headless Python test-suite.

metadata#

An instance of a Python dict.

One or more traits can be passed to the constructor to validate the keys and/or values of the dict. If you need more detailed validation, you may use a custom validator method.

Changed in version 5.0: Added key_trait for validating dict keys.

Changed in version 5.0: Deprecated ambiguous trait, traits args in favor of value_trait, per_key_traits.

positions#

An instance of a Python list.

selections#

An instance of a Python list.

roi_mode#

A trait for unicode strings.

view_size#

An integer trait.

auto_save#

A boolean (True, False) trait.

preview_frame#

An integer trait.

__init__(source, *, roi_mode='single', save_dir=None, preview_frame=None, **kwargs)[source]#

Build the dashboard from a source (no pixel reads at construction).

Parameters:
  • source – A SequenceFile, or a path/str that is opened via open_sequence().

  • roi_mode (str) – "single" (<=1 ROI/position) or "multi".

  • save_dir – Default output directory for save() (and hence for auto-save, which is on by default). None keeps the previous behaviour of writing into the current working directory.

  • preview_frame (int | None) – Which frame the gallery thumbnails and the ROI editor open on. None (the default) picks the middle frame, num_timepoints // 2: in a growing culture frame 0 is typically empty, so opening there gives no indication whether a chamber holds cells at all. Clamped into range. Note this indexes the source’s timepoints – if a later export step truncates the sequence, pick a frame inside that range (see anchor_frame).

  • **kwargs – Forwarded to anywidget.AnyWidget (e.g. auto_save to start with auto-save switched off).

Raises:

traitlets.TraitError – If preview_frame is negative.

Return type:

None

property manifest#

Build a SelectionManifest from current state.

save(directory=None)[source]#

Write selection.json (+ previews) via save_selection().

Parameters:

directory – Output dir; defaults to the save_dir passed to the constructor, and failing that to the current working directory (the notebook’s dir at run time).

Returns:

The path to the written selection.json.

Return type:

str

classmethod resume(manifest_or_path, source=None, **kwargs)[source]#

Reopen a dashboard pre-populated from a saved selection.json.

Lets a curation session be saved with save() and continued later in a fresh dashboard, instead of starting over.

Parameters:
  • manifest_or_path – A path to a selection.json file (or its containing directory), or an already-loaded SelectionManifest.

  • sourceNone to reopen the manifest’s own source path, a path/str to apply the selections to a different file, or an already-open SequenceFile – same convention as load_selection().

  • **kwargs – Forwarded to the constructor (e.g. roi_mode to override the manifest’s saved mode).

Returns:

A SequenceDashboard with .selections restored.

Raises:

ValueError – If a selection’s position is out of range for source.

Return type:

SequenceDashboard

class acia.notebook.RegistrationDashboard[source]#

Bases: AnyWidget

Pick + verify + batch-apply a drift-correction method (anywidget).

Pick one of the 5 RegistrationMethod implementations (default "GradientECC"), verify it on sampled frames of a single position (drift trajectory + before/after), then batch-apply it across every position/frame of the acquisition with live progress and resumability. Frames are read lazily from the source; the widget never loads a whole (possibly hundreds-of-GB) file, and batch-apply holds at most one position’s frames in memory at a time.

MaskedTemplateCorrelation additionally needs a mask_rect (RotatedCropSpec): the mask_* traits and the ESM’s mask editor port ROICropper’s click-to-fit + drag/resize/rotate interaction model (_fit_rotated_rect() is the same geometry helper SequenceDashboard’s point-fit tool uses) – ROICropper itself is not touched.

Works in Jupyter/Colab and in marimo via mo.ui.anywidget(dash). The ESM is best-effort and verified only by a real notebook run, not by the headless Python test-suite (no ESM/Playwright suite for this widget in v1, per the spec).

metadata#

An instance of a Python dict.

One or more traits can be passed to the constructor to validate the keys and/or values of the dict. If you need more detailed validation, you may use a custom validator method.

Changed in version 5.0: Added key_trait for validating dict keys.

Changed in version 5.0: Deprecated ambiguous trait, traits args in favor of value_trait, per_key_traits.

positions#

An instance of a Python list.

method_name#

A trait for unicode strings.

n_sample_frames#

An integer trait.

mask_center_x#

A float trait.

mask_center_y#

A float trait.

mask_width#

An integer trait.

mask_height#

An integer trait.

mask_angle#

A float trait.

mask_points#

An instance of a Python list.

mask_image_b64#

A trait for unicode strings.

mask_image_w#

An integer trait.

mask_image_h#

An integer trait.

batch_running#

A boolean (True, False) trait.

__init__(source, *, method_name='GradientECC', method_kwargs=None, reference_mode='reanchor', low_confidence='keep', **kwargs)[source]#

Build the dashboard from a source (no pixel reads at construction).

Parameters:
  • source – A SequenceFile, or a path/str that is opened via open_sequence().

  • method_name (str) – The initially-selected RegistrationMethod name; one of _REGISTRATION_METHOD_NAMES.

  • method_kwargs (dict | None) – Constructor keyword arguments for the chosen method, e.g. {"min_confidence": 0.8} or {"exclude_rects": [...]} for GradientECC. Deliberately a plain attribute rather than a synced trait: arbitrary Python objects (RotatedCropSpec instances) must not be pushed across the widget comm.

  • reference_mode (str) – The reference policy batch-apply registers under; one of MODES. Defaults to "reanchor", which only changes what happens to a frame that would otherwise be recorded as a failure. Pass "fixed" to always compare against frame 0.

  • low_confidence (str) – What the registration method does with a fit scoring below its own confidence threshold; one of LOW_CONFIDENCE_POLICIES. Defaults to "keep", so every frame ends up with a stored transform and a weak fit is reported through its confidence (and a warning) rather than by being missing. Pass "reject" to record those frames in failed_frames instead, leaving them without a transform. Forwarded to the method as on_low_confidence; an explicit on_low_confidence in method_kwargs wins. Methods with no confidence gate ignore it.

  • **kwargs – Forwarded to anywidget.AnyWidget.

Raises:

ValueError – If reference_mode or low_confidence is not a known value.

Return type:

None

property mask_rect: RotatedCropSpec | None#

The current mask rect, or None if none has been drawn yet.

batch_apply(directory=None, positions=None, sources=None, method_kwargs=None)[source]#

Estimate transforms for every (or a subset of) position, live.

For the currently-selected method_name, processes every position in positions (default: all), one at a time, estimating a FrameTransform per frame against that position’s own frame 0. Sends a "progress" message (with best-effort elapsed_seconds/eta_seconds) after every frame, and persists the manifest both after every position and periodically within a position (every CHECKPOINT_INTERVAL newly-estimated frames), so an interrupted run can be resumed. A position already fully complete (every frame accounted for in transforms/failed_frames) is skipped; a partial one resumes from its first uncomputed frame instead of being re-skipped or fully redone. A prior record recorded under a different method_name is never treated as resume/skip data for the currently-selected method – the position is processed from scratch instead of silently merging frames across methods. A whole-position failure (whether from _register_position itself or from the resume/skip bookkeeping above it, e.g. a size_t lookup) never aborts the rest of the run, and never discards progress already checkpointed for that position in this or a prior run – the failure is recorded as a note on top of whatever record (checkpointed or pre-existing) is already known, not as a fresh empty one.

Because a complete position is skipped and a partial one resumes by count, re-running over an existing registration_transforms.json never re-estimates frames a previous run already recorded – including ones it recorded as failures. Changing low_confidence (or any method setting) therefore does not retroactively fix an existing file: delete it, or the affected records, and register those positions again.

Parameters:
  • directory – Output directory for registration_transforms.json; defaults to the current working directory. Also the path consulted for already-completed positions to skip.

  • positions – Optional subset of position indices to process; defaults to every position in the acquisition.

  • sources – Optional {position: ImageSequenceSource} override – when a position has an entry, that source is registered instead of self._file.position(position), and its own size_t (not the full position’s) is what “already complete” is checked against. Lets a caller limit registration to a sub-range via the lazy numpy-style indexing every ImageSequenceSource already supports, e.g. sources={2: seqfile.position(2)[:30]} to register only the first 30 frames of position 2. A position absent from sources (or when sources is None) falls back to the whole position, unchanged from before.

  • method_kwargs – Constructor overrides for the registration method, applied to this call only and layered over the dashboard’s own method_kwargs. The intended use is settings that differ per position – calling this once per position with that position’s own GradientECC exclude_rects. Not recorded in the manifest: method_params is a single manifest-level dict, so per-position settings have nowhere to go without mislabelling one position’s values as another’s.

Returns:

dict{"num_positions", "completed", "skipped", "failed_positions", "path"}.

Raises:
  • RuntimeError – If a batch-apply run is already in progress.

  • ValueError – If method_name is unknown, or MaskedTemplateCorrelation is selected without a mask rect.

Return type:

dict

property manifest: RegistrationManifest#

Build a RegistrationManifest from the accumulated RegistrationRecord results (mirrors SequenceDashboard.manifest building a SelectionManifest).

save(directory=None)[source]#

Write registration_transforms.json via save_registration().

Parameters:

directory – Output dir; defaults to the current working directory (the notebook’s dir at run time).

Returns:

The path to the written registration_transforms.json.

Return type:

str