API#
In addition to declaring a schema (which is intended to be language agnostic),
useq-schema
offers a python API for working with
MDASequence
and MDAEvent
objects.
MDASequence
#
A sequence of MDA (Multi-Dimensional Acquisition) events.
This is the core object in the useq
library, and is used define a sequence of
events to be run on a microscope. It object may be constructed manually, or from
file (e.g. json or yaml).
The object itself acts as an iterator for useq.MDAEvent
objects:
Attributes:
Name | Type | Description |
---|---|---|
metadata |
dict
|
A dictionary of user metadata to be stored with the sequence. |
axis_order |
str
|
The order of the axes in the sequence. Must be a permutation of |
stage_positions |
tuple[Position, ...]
|
The stage positions to visit. (each with |
grid_plan |
GridFromEdges | GridRelative | None
|
The grid plan to follow. One of |
channels |
tuple[Channel, ...]
|
The channels to acquire. see |
time_plan |
MultiPhaseTimePlan | TIntervalDuration | TIntervalLoops | TDurationLoops | None
|
The time plan to follow. One of |
z_plan |
ZTopBottom | ZRangeAround | ZAboveBelow | ZRelativePositions | ZAbsolutePositions | None
|
The z plan to follow. One of |
uid |
UUID
|
A read-only unique identifier (uuid version 4) for the sequence. This will be generated, do not set. |
autofocus_plan |
AxesBasedAF | None
|
The hardware autofocus plan to follow. One of |
keep_shutter_open_across |
tuple[str, ...]
|
A tuple of axes |
Examples:
Create a MDASequence
>>> from useq import MDASequence, Position, Channel, TIntervalDuration
>>> seq = MDASequence(
... axis_order="tpgcz",
... time_plan={"interval": 0.1, "loops": 2},
... stage_positions=[(1, 1, 1)],
... grid_plan={"rows": 2, "columns": 2},
... z_plan={"range": 3, "step": 1},
... channels=[{"config": "DAPI", "exposure": 1}]
... )
Print the sequence to visualize its structure
>>> print(seq)
... MDASequence(
... stage_positions=(Position(x=1.0, y=1.0, z=1.0, name=None),),
... grid_plan=GridRowsColumns(
... fov_width=None,
... fov_height=None,
... overlap=(0.0, 0.0),
... mode=<OrderMode.row_wise_snake: 'row_wise_snake'>,
... rows=2,
... columns=2,
... relative_to=<RelativeTo.center: 'center'>
... ),
... channels=(
... Channel(
... config='DAPI',
... group='Channel',
... exposure=1.0,
... do_stack=True,
... z_offset=0.0,
... acquire_every=1,
... camera=None
... ),
... ),
... time_plan=TIntervalLoops(
... prioritize_duration=False,
... interval=datetime.timedelta(microseconds=100000),
... loops=2
... ),
... z_plan=ZRangeAround(go_up=True, range=3.0, step=1.0)
... )
Iterate over the events in the sequence
>>> print(list(seq))
... [
... MDAEvent(
... index=mappingproxy({'t': 0, 'p': 0, 'g': 0, 'c': 0, 'z': 0}),
... channel=Channel(config='DAPI'),
... exposure=1.0,
... min_start_time=0.0,
... x_pos=0.5,
... y_pos=1.5,
... z_pos=-0.5
... ),
... MDAEvent(
... index=mappingproxy({'t': 0, 'p': 0, 'g': 0, 'c': 0, 'z': 1}),
... channel=Channel(config='DAPI'),
... exposure=1.0,
... min_start_time=0.0,
... x_pos=0.5,
... y_pos=1.5,
... z_pos=0.5
... ),
... ...
... ]
Print the sequence as yaml
>>> print(seq.yaml())
axis_order:
- t
- p
- g
- c
- z
channels:
- config: DAPI
exposure: 1.0
grid_plan:
columns: 2
rows: 2
stage_positions:
- x: 1.0
y: 1.0
z: 1.0
time_plan:
interval: '0:00:00.100000'
loops: 2
z_plan:
range: 3.0
step: 1.0
shape: Tuple[int, ...]
property
#
Return the shape of this sequence.
Note
This doesn't account for jagged arrays, like channels that exclude z stacks or skip timepoints.
sizes: Mapping[str, int]
property
#
Mapping of axis name to size of that axis.
uid: UUID
property
#
A unique identifier for this sequence.
used_axes: str
property
#
Single letter string of axes used in this sequence, e.g. ztc
.
__eq__(other: Any) -> bool
#
Return True
if two MDASequences
are equal (uid is excluded).
__iter__() -> Iterator[MDAEvent]
#
Same as iter_events
. Supports for event in sequence: ...
syntax.
estimate_duration() -> TimeEstimate
#
Estimate duration and other timing issues of an MDASequence.
Notable mis-estimations may include:
- when the time interval is shorter than the time it takes to acquire the data
and any of the channels have acquire_every
> 1
- when channel exposure times are omitted. In this case, we assume 1ms exposure.
Returns:
Type | Description |
---|---|
TimeEstimate
|
A named 3-tuple with the following fields: - total_duration: float Estimated total duration of the experiment, in seconds. - per_t_duration: float Estimated duration of a single timepoint, in seconds. - time_interval_exceeded: bool Whether the time interval between timepoints is shorter than the time it takes to acquire the data |
iter_axis(axis: str) -> Iterator[Channel | float | PositionBase]
#
Iterate over the positions or items of a given axis.
iter_events() -> Iterator[MDAEvent]
#
Iterate over all events in the MDA sequence.
See source of useq._mda_sequence.iter_sequence for details on how events are constructed and yielded.
Yields:
Type | Description |
---|---|
MDAEvent
|
Each event in the MDA sequence. |
iter_sequence(sequence)
#
Iterate over all events in the MDA sequence.'.
Note
This method will usually be used via useq.MDASequence.iter_events
, or by
simply iterating over the sequence.
This does the job of iterating over all the frames in the MDA sequence, handling the logic of merging all z plans in channels and stage positions defined in the plans for each axis.
The is the most "logic heavy" part of useq-schema
(the rest of which is
almost entirely declarative). This iterator is useful for consuming MDASequence
objects in a python runtime, but it isn't considered a "core" part of the schema.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
sequence
|
MDASequence
|
The sequence to iterate over. |
required |
Yields:
Type | Description |
---|---|
MDAEvent
|
Each event in the MDA sequence. |
Source code in src/useq/_iter_sequence.py
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
|