Source code for acia.timing
"""Helpers for physical calibration (time and pixel size) in pint units.
Sequences and overlays carry an optional physical calibration:
* ``timepoints`` -- a per-frame pint ``Quantity`` array (time of each frame),
specified at load either explicitly or via a scalar ``frame_interval``;
* ``pixel_size`` -- a pint length per pixel (isotropic scalar, or a 2-element
``[y, x]`` Quantity for anisotropic pixels).
These helpers normalise user-supplied values into pint quantities.
"""
from __future__ import annotations
import numpy as np
from acia import Q_, ureg
[docs]
def to_quantity(value):
"""Coerce a value to a pint ``Quantity`` (parse strings like ``"15 minute"``)."""
if value is None:
return None
if isinstance(value, ureg.Quantity):
return value
return Q_(value)
[docs]
def resolve_timepoints(n: int, *, timepoints=None, frame_interval=None):
"""Return a length-``n`` pint ``Quantity`` of per-frame timepoints, or ``None``.
Args:
n: number of frames.
timepoints: explicit per-frame times as a pint ``Quantity`` array.
frame_interval: scalar time between frames (pint ``Quantity`` or a string
like ``"15 minute"``); yields ``arange(n) * interval``.
"""
if timepoints is not None:
if not isinstance(timepoints, ureg.Quantity):
raise TypeError(
"timepoints must be a pint Quantity array, e.g. "
"Q_(np.array([0, 15, 30]), 'minute')"
)
if len(timepoints) != n:
raise ValueError(
f"timepoints length {len(timepoints)} does not match the number "
f"of frames {n}"
)
return timepoints
if frame_interval is not None:
interval = to_quantity(frame_interval)
return np.arange(n) * interval
return None