zea.data.spec

Functions

check_dtype(value, expected_dtype)

Check if the dtype of a value matches the expected dtype, allowing for compatible types.

find_matched_shape(value, expected_shapes)

Find the first expected shape specification that matches the shape of the value.

match_shape(value, expected_shape)

Check if the shape of a value matches the expected shape specification.

value_shape(value)

Return the shape tuple for numpy arrays and scalar values.

Classes

AlignedData(values[, labels])

Time-of-flight corrected data.

Annotations([anatomy, view, label, ...])

Frame-level annotations, either one per frame or a single broadcast value.

AttenuationMap(values[, coordinates, ...])

Acoustic attenuation map with per-pixel Cartesian coordinates.

BeamformedData(values[, coordinates, ...])

Beamformed (beamsummed) data with per-pixel Cartesian coordinates.

BooleanMap(values[, coordinates, ...])

Map data with bool pixel values and per-pixel Cartesian coordinates.

ColorDopplerMap(values[, coordinates, ...])

Color Doppler (velocity) data with per-pixel Cartesian coordinates.

DataSpec([raw_data, aligned_data, ...])

Data group containing raw channels, derived pipeline products, and optional spatial maps.

EnvelopeData(values[, coordinates, ...])

Envelope-detected data with per-pixel Cartesian coordinates.

FileSpec([data, scan, tracks, ...])

A dataset containing all the data, scan parameters, metadata, and metrics for a single acquisition.

FloatMap(values[, coordinates, timestamps, ...])

Map data with float32 pixel values and per-pixel Cartesian coordinates.

Image(values[, coordinates, timestamps, ...])

Reconstructed (log-compressed) image data with per-pixel Cartesian coordinates.

Map(values[, coordinates, timestamps, ...])

Map data with per-pixel Cartesian coordinates.

MetadataSpec([subject, credit, probe_pose, ...])

Metadata group with subject, acquisition context, annotations, and extra signals.

MetricsSpec([common_midpoint_phase_error, ...])

Metrics group for acquisition-level quality/performance metrics.

ProbePose(start_time_offset, translation, ...)

Sampled probe pose metadata at the tip of the transducer.

ProbeSpec([name, type, ...])

Probe hardware specification.

ScanSpec(sampling_frequency, ...[, ...])

Scan group with acquisition and transmit metadata.

Segmentation(values[, coordinates, ...])

Segmentation data with per-pixel Cartesian coordinates.

ShearWaveElastographyMap(values[, ...])

Shear-wave elastography data with per-pixel Cartesian coordinates.

Signal(start_time_offset, *[, ...])

Base class for additional signals with timing metadata.

Signal1D(start_time_offset, samples, *[, ...])

One-dimensional sampled signal with timing metadata.

SignalND(start_time_offset, samples, *[, ...])

N-dimensional sampled signal with timing metadata.

SosMap(values[, coordinates, timestamps, ...])

Speed-of-sound map data with per-pixel Cartesian coordinates.

Spec()

Base class for data specifications with schema validation.

StrainPercentageMap(values[, coordinates, ...])

Strain map data with per-pixel Cartesian coordinates.

Subject([id, type, age, sex, weight, ...])

Subject metadata associated with the study.

TissueDopplerMap(values[, coordinates, ...])

Tissue Doppler data with per-pixel Cartesian coordinates.

TrackSpec([data, scan, label, transmit_only])

A single acquisition track with its own data and scan parameters.

UnsignedIntMap(values[, coordinates, ...])

Map data with uint8 pixel values and per-pixel Cartesian coordinates.

class zea.data.spec.AlignedData(values, labels=None)[source]

Bases: Spec

Time-of-flight corrected data.

Parameters:
  • values (ndarray) – The aligned data of shape (n_frames, n_tx, n_ax, n_el, n_ch) and type float32 or int16. n_ch is 1 for RF data or 2 for IQ data.

  • labels (ndarray | None) – The labels for the channel dimension, e.g. ["RF"] or ["I", "Q"]. Auto-generated from n_ch if not provided.

FIELD_METADATA: ClassVar[dict[str, Any]] = {'labels': {'description': "Channel labels, e.g. 'RF' or ['I', 'Q'].", 'unit': '–'}, 'values': {'description': 'Time-of-flight corrected channel data.', 'unit': '–'}}
labels: ndarray | None = None
values: ndarray
class zea.data.spec.Annotations(anatomy=None, view=None, label=None, image_quality=None)[source]

Bases: Spec

Frame-level annotations, either one per frame or a single broadcast value.

Parameters:
  • anatomy (ndarray | str | None) – Anatomical structure imaged, e.g. carotid, liver, thyroid.

  • view (ndarray | str | None) – Imaging plane/orientation, e.g. longitudinal, transverse, apical_4_chamber.

  • label (ndarray | str | None) – Pathology or classification label, e.g. benign, malignant.

  • image_quality (ndarray | str | None) – Image quality label, e.g. low, mid, high.

FIELD_METADATA: ClassVar[dict[str, Any]] = {'anatomy': {'description': 'Anatomical structure imaged (e.g. carotid, liver).', 'unit': '–'}, 'image_quality': {'description': 'Image quality label.', 'rare': True, 'unit': '–'}, 'label': {'description': 'Pathology or classification label.', 'unit': '–'}, 'view': {'description': 'Imaging plane/orientation (e.g. longitudinal, apical_4_chamber).', 'unit': '–'}}
anatomy: ndarray | str | None = None
image_quality: ndarray | str | None = None
label: ndarray | str | None = None
view: ndarray | str | None = None
class zea.data.spec.AttenuationMap(values, coordinates=None, timestamps=None, start_time_offset=None, labels=None, description=None, unit=None, min=None, max=None, gamma=1.0)[source]

Bases: FloatMap

Acoustic attenuation map with per-pixel Cartesian coordinates.

Acoustic attenuation describes the loss of acoustic energy as the wave propagates through tissue (through absorption and scattering). Attenuation is frequency dependent and is modelled here with the usual power law

\[\alpha(f) = \alpha_0 \, f^{\gamma},\]

where \(\alpha_0\) is the per-pixel attenuation coefficient stored in values and \(\gamma\) is the (scalar) power-law exponent stored in gamma. Reporting the coefficient normalized by frequency makes values comparable across systems and transmit frequencies.

The coefficient is stored in the spec’s base units of dB/m/Hz (rather than the common clinical dB/cm/MHz; note 1 dB/cm/MHz = 1e-4 dB/m/Hz). Strictly, when \(\gamma \neq 1\) the coefficient carries the exponent in its units (dB/m/Hz**gamma); the dB/m/Hz label reflects the linear (\(\gamma = 1\)) convention.

The exponent is close to 1 for most soft tissue (attenuation is roughly linear in frequency), e.g. liver \(\gamma \approx 1.14\), breast \(\gamma \approx 1.5\), while water / low-loss viscous media follow \(\gamma = 2\). It defaults to 1.0 (linear), which reproduces the plain frequency-normalized “attenuation coefficient slope”.

Parameters:
  • values (ndarray) – The attenuation coefficient \(\alpha_0\) in dB/m/Hz of shape (n_frames, z, x, y) and type float32.

  • coordinates (ndarray | None) – Per-pixel Cartesian positions in metres, shape (n_frames, z, x, 3) or (n_frames, z, x, y, 3). The leading frame axis may be omitted to broadcast one coordinate grid across all frames.

  • gamma (float) – Scalar power-law exponent \(\gamma\) of the frequency dependence \(\alpha(f) = \alpha_0 f^{\gamma}\). Defaults to 1.0 (linear frequency dependence).

FIELD_METADATA: ClassVar[dict[str, Any]] = {'coordinates': {'description': 'Per-pixel Cartesian positions (x, y, z) in metres.', 'unit': 'm'}, 'description': {'description': 'Free-text description of the map contents.', 'rare': True, 'unit': '–'}, 'gamma': {'description': 'Power-law exponent of the frequency dependence alpha(f) = alpha_0 * f**gamma. 1.0 is linear (soft tissue ~1-1.5, e.g. liver ~1.14), 2.0 for water.', 'rare': True, 'unit': '–'}, 'labels': {'description': 'Labels for each channel in values.', 'rare': True, 'unit': '–'}, 'max': {'description': 'Maximum value of the map.', 'rare': True, 'unit': '–'}, 'min': {'description': 'Minimum value of the map.', 'rare': True, 'unit': '–'}, 'start_time_offset': {'description': 'Time offset between the first transmit event of the ultrasound acquisition and frame 0 of this map. Negative means frame 0 was acquired before the first transmit event; positive means it was acquired after.', 'rare': True, 'unit': 's'}, 'timestamps': {'description': 'Per-frame acquisition timestamps relative to frame 0.', 'rare': True, 'unit': 's'}, 'unit': {'description': "Physical unit of the map values, e.g. 'm/s', '%'.", 'rare': True, 'unit': '–'}, 'values': {'description': 'Map pixel values.', 'unit': '–'}}
gamma: float = 1.0
class zea.data.spec.BeamformedData(values, coordinates=None, timestamps=None, start_time_offset=None, labels=None, description=None, unit=None, min=None, max=None)[source]

Bases: FloatMap

Beamformed (beamsummed) data with per-pixel Cartesian coordinates.

Parameters:
  • values (ndarray) – The beamformed data of shape (n_frames, z, x, n_ch) or (n_frames, z, x, y, n_ch) and type float32. n_ch is 1 for RF data or 2 for IQ data.

  • coordinates (ndarray | None) – Per-pixel Cartesian positions in metres, shape (n_frames, z, x, 3) or (n_frames, z, x, y, 3). The leading frame axis may be omitted to broadcast one coordinate grid across all frames.

  • labels (ndarray | None) – The labels for the channel dimension, e.g. ["RF"] or ["I", "Q"]. Auto-generated from n_ch if not provided.

class zea.data.spec.BooleanMap(values, coordinates=None, timestamps=None, start_time_offset=None, labels=None, description=None, unit=None, min=None, max=None)[source]

Bases: Map

Map data with bool pixel values and per-pixel Cartesian coordinates.

class zea.data.spec.ColorDopplerMap(values, coordinates=None, timestamps=None, start_time_offset=None, labels=None, description=None, unit=None, min=None, max=None)[source]

Bases: FloatMap

Color Doppler (velocity) data with per-pixel Cartesian coordinates.

Parameters:
  • values (ndarray) – The color Doppler velocity values in m/s of shape (n_frames, z, x, y) and type float32. Positive values indicate flow towards the transducer, negative values indicate flow away from the transducer.

  • coordinates (ndarray | None) – Per-pixel Cartesian positions in metres.

class zea.data.spec.DataSpec(raw_data=None, aligned_data=None, beamformed_data=None, envelope_data=None, image=None, segmentation=None, sos_map=None, attenuation_map=None, strain_percentage_map=None, shear_wave_elastography_map=None, tissue_doppler=None, color_doppler=None, **extra_maps)[source]

Bases: Spec

Data group containing raw channels, derived pipeline products, and optional spatial maps.

Plain-array data products:
raw_data: Raw channel data of shape (n_frames, n_tx, n_ax, n_el, n_ch)

and type float32 or int16.

Grouped data products (values + optional metadata):
  • aligned_data: Time-of-flight corrected data and optional labels.

  • beamformed_data: Beamformed (beamsummed) data and per-pixel coordinates.

  • envelope_data: Envelope-detected data and per-pixel coordinates.

  • image: Reconstructed image data and per-pixel coordinates.

  • segmentation: Segmentation data and per-pixel coordinates.

  • sos_map: Speed-of-sound map data and per-pixel coordinates.

  • attenuation_map: Acoustic attenuation map data and per-pixel coordinates.

  • strain_percentage_map: Strain map data and per-pixel coordinates.

  • shear_wave_elastography_map: Shear-wave elastography data and per-pixel coordinates.

  • tissue_doppler: Tissue Doppler data and per-pixel coordinates.

  • color_doppler: Color Doppler velocity data and per-pixel coordinates.

  • **kwargs: Any other spatially aligned map data and per-pixel coordinates.

At least one data field (plain-array or grouped) must be provided.

FIELD_METADATA: ClassVar[dict[str, Any]] = {'aligned_data': {'description': 'Time-of-flight corrected data.', 'rare': True}, 'attenuation_map': {'description': 'Acoustic attenuation map data.', 'rare': True}, 'beamformed_data': {'description': 'Beamformed data.', 'rare': True}, 'color_doppler': {'description': 'Color Doppler velocity data.', 'rare': True}, 'envelope_data': {'description': 'Envelope-detected data.', 'rare': True}, 'image': {'description': 'Reconstructed image data.', 'rare': True}, 'raw_data': {'description': 'Raw channel data.', 'unit': '–'}, 'segmentation': {'description': 'Segmentation data.', 'rare': True}, 'shear_wave_elastography_map': {'description': 'Shear-wave elastography data.', 'rare': True}, 'sos_map': {'description': 'Speed-of-sound map data.', 'rare': True}, 'strain_percentage_map': {'description': 'Strain map data.', 'rare': True}, 'tissue_doppler': {'description': 'Tissue Doppler data.', 'rare': True}}
aligned_data: AlignedData | dict | None = None
attenuation_map: AttenuationMap | dict | None = None
beamformed_data: BeamformedData | dict | None = None
color_doppler: ColorDopplerMap | dict | None = None
envelope_data: EnvelopeData | dict | None = None
image: Image | dict | None = None
raw_data: ndarray | None = None
segmentation: Segmentation | dict | None = None
shear_wave_elastography_map: ShearWaveElastographyMap | dict | None = None
sos_map: SosMap | dict | None = None
strain_percentage_map: StrainPercentageMap | dict | None = None
tissue_doppler: TissueDopplerMap | dict | None = None
class zea.data.spec.EnvelopeData(values, coordinates=None, timestamps=None, start_time_offset=None, labels=None, description=None, unit=None, min=None, max=None)[source]

Bases: FloatMap

Envelope-detected data with per-pixel Cartesian coordinates.

Parameters:
  • values (ndarray) – The envelope data of shape (n_frames, z, x) or (n_frames, z, x, y) and type float32.

  • coordinates (ndarray | None) – Per-pixel Cartesian positions in metres, shape (*values.shape, 3). The leading frame axis may be omitted to broadcast one coordinate grid across all frames.

class zea.data.spec.FileSpec(data=None, scan=None, tracks=None, track_schedule=None, metadata=None, metrics=None, probe_name=None, probe=None, us_machine=None, description=None, acquisition_time=None, custom=None)[source]

Bases: Spec

A dataset containing all the data, scan parameters, metadata, and metrics for a single acquisition.

A FileSpec always contains at least one track. When data and scan are supplied at construction time they are transparently wrapped into a single TrackSpec, so all existing call-sites continue to work unchanged. For multi-track files pass tracks directly.

Parameters:
  • data (DataSpec | dict | None) – Data for a single-track acquisition (wrapped into tracks[0]).

  • scan (ScanSpec | dict | None) – Scan parameters for a single-track acquisition.

  • tracks (list | None) – Explicit list of TrackSpec objects (multi-track mode). Mutually exclusive with data/scan.

  • track_schedule (ndarray | None) – 1-D int32 array of length n_total_tx giving the track index for each global transmit event.

  • metadata (MetadataSpec | dict | None) – Additional metadata about the acquisition.

  • metrics (MetricsSpec | dict | None) – Metrics computed from the acquisition.

  • probe (ProbeSpec | dict | None) – Physical probe specification (see ProbeSpec). The probe name is stored as probe.name; use zea.File.probe_name to read it back from an HDF5 file.

  • us_machine (str | None) – The ultrasound machine used to acquire the data.

  • description (str | None) – Free-text description.

  • custom (list | None) – Optional list of CustomElement objects holding data that does not fit the zea format. These are written to a custom group.

Example

>>> from datetime import datetime, timezone
>>> from zea.data.spec import FileSpec
>>> import numpy as np

>>> dataset = FileSpec(
...     data={
...         "raw_data": np.zeros((2, 4, 64, 8, 1), dtype=np.float32),
...     },
...     scan={
...         "sampling_frequency": np.float32(40e6),
...         "center_frequency": np.float32(5e6),
...         "demodulation_frequency": np.float32(5e6),
...         "initial_times": np.zeros(4, dtype=np.float32),
...         "t0_delays": np.zeros((4, 8), dtype=np.float32),
...         "tx_apodizations": np.ones((4, 8), dtype=np.float32),
...         "focus_distances": np.full(4, np.inf, dtype=np.float32),
...         "transmit_origins": np.zeros((4, 3), dtype=np.float32),
...         "polar_angles": np.zeros(4, dtype=np.float32),
...     },
...     probe={"name": "test_probe", "probe_geometry": np.zeros((8, 3))},
...     acquisition_time=datetime.now(timezone.utc).isoformat(),
... )
>>> dataset.data.raw_data.shape
(2, 4, 64, 8, 1)
>>> dataset.acquisition_time is not None
True
FIELD_METADATA: ClassVar[dict[str, Any]] = {'acquisition_time': {'description': "UTC acquisition timestamp in ISO 8601 format (e.g. '2026-06-12T14:30:00+00:00'). Optional not recorded when omitted."}}
acquisition_time: str | None = None
custom: list
property data: DataSpec

Return the DataSpec of the single track.

Raises AttributeError when the file has more than one track — use spec.tracks[i].data instead.

description: str | None = None
metadata: MetadataSpec | dict
metrics: MetricsSpec | dict
probe: ProbeSpec | dict | None = None
save(path, compression=Blosc(cname='zstd', clevel=7, shuffle=2), chunk_axes=('n_frames',), warn_missing_optional_fields=True)[source]

Save the dataset to the specified path.

Return type:

None

property scan: ScanSpec | None

Return the ScanSpec of the single track.

Raises AttributeError when the file has more than one track — use spec.tracks[i].scan instead.

to_dict()[source]

Return this spec as a nested dictionary.

Includes all SCHEMA fields plus the tracks list.

Return type:

dict

track_schedule: ndarray | None = None
tracks: list
us_machine: str | None = None
class zea.data.spec.FloatMap(values, coordinates=None, timestamps=None, start_time_offset=None, labels=None, description=None, unit=None, min=None, max=None)[source]

Bases: Map

Map data with float32 pixel values and per-pixel Cartesian coordinates.

class zea.data.spec.Image(values, coordinates=None, timestamps=None, start_time_offset=None, labels=None, description=None, unit=None, min=None, max=None)[source]

Bases: Map

Reconstructed (log-compressed) image data with per-pixel Cartesian coordinates.

Parameters:
  • values (ndarray) – The image values of shape (n_frames, z, x, y) or (n_frames, z, x) and type uint8 or float32. For float32 values, the values should be in dB (between -inf and 0).

  • coordinates (ndarray | None) – Per-pixel Cartesian positions in metres, shape (*values.shape, 3). The leading frame axis may be omitted to broadcast one coordinate grid across all frames.

class zea.data.spec.Map(values, coordinates=None, timestamps=None, start_time_offset=None, labels=None, description=None, unit=None, min=None, max=None)[source]

Bases: Spec

Map data with per-pixel Cartesian coordinates.

A map is a function from Cartesian space to some real values: every pixel at spatial index [f, i, j, ...] is assigned a 3-D position coordinates[f, i, j, ..., :] = [x, y, z] in metres.

The most flexible map spec, which can be used for any spatially aligned data product. See, for example, cartesian_pixel_grid() or polar_pixel_grid() to create a suitable coordinate array from your scan geometry.

Parameters:
  • values (ndarray) – The map values of shape (n_frames, z, x, y, n_ch) or (n_frames, z, x, y) or (n_frames, z, x, n_ch) or (n_frames, z, x) and type uint8, float32, int16, or complex64.

  • coordinates (ndarray | None) – Per-pixel Cartesian positions in metres, shape (*spatial_dims, 3) where spatial_dims matches the spatial (non-channel) dimensions of values. For non-channeled values the shape is (*values.shape, 3); for channeled values the shape is (*values.shape[:-1], 3). The last axis holds [x, y, z]. The leading n_frames axis may be omitted to broadcast one coordinate grid across all frames.

  • timestamps (ndarray | None) – Optional per-frame acquisition timestamps in seconds, shape (n_frames,), relative to frame 0. Use this to record the time of each frame when the sampling is irregular. Must start at 0 and be strictly increasing. Requires start_time_offset to also be provided.

  • start_time_offset (ndarray | float | None) – Time offset in seconds between the first transmit event of the ultrasound acquisition and frame 0 of this map. Negative means frame 0 was acquired before the first transmit event; positive means it was acquired after. Required when timestamps is provided.

  • labels (ndarray | None) – The labels corresponding to the n_ch channels in the values. This is required when values have an n_ch dimension, and should be None otherwise. For IQ data, this would typically be ["I", "Q"].

  • description (str | None) – An optional free-text description of the map.

  • unit (str | None) – An optional string specifying the physical unit of the map values, e.g. "m/s", "%", etc.

  • min (float | None) – The minimum value of the map.

  • max (float | None) – The maximum value of the map.

FIELD_METADATA: ClassVar[dict[str, Any]] = {'coordinates': {'description': 'Per-pixel Cartesian positions (x, y, z) in metres.', 'unit': 'm'}, 'description': {'description': 'Free-text description of the map contents.', 'rare': True, 'unit': '–'}, 'labels': {'description': 'Labels for each channel in values.', 'rare': True, 'unit': '–'}, 'max': {'description': 'Maximum value of the map.', 'rare': True, 'unit': '–'}, 'min': {'description': 'Minimum value of the map.', 'rare': True, 'unit': '–'}, 'start_time_offset': {'description': 'Time offset between the first transmit event of the ultrasound acquisition and frame 0 of this map. Negative means frame 0 was acquired before the first transmit event; positive means it was acquired after.', 'rare': True, 'unit': 's'}, 'timestamps': {'description': 'Per-frame acquisition timestamps relative to frame 0.', 'rare': True, 'unit': 's'}, 'unit': {'description': "Physical unit of the map values, e.g. 'm/s', '%'.", 'rare': True, 'unit': '–'}, 'values': {'description': 'Map pixel values.', 'unit': '–'}}
coordinates: ndarray | None = None
description: str | None = None
labels: ndarray | None = None
max: float | None = None
min: float | None = None
start_time_offset: ndarray | float | None = None
timestamps: ndarray | None = None
unit: str | None = None
values: ndarray
class zea.data.spec.MetadataSpec(subject=None, credit=None, probe_pose=None, voice_narration=None, ecg=None, text_report=None, annotations=None, **extra_signals)[source]

Bases: Spec

Metadata group with subject, acquisition context, annotations, and extra signals.

FIELD_METADATA: ClassVar[dict[str, Any]] = {'annotations': {'description': 'Frame-level annotations.', 'rare': True, 'unit': '–'}, 'credit': {'description': 'Credit or attribution for the dataset.', 'unit': '–'}, 'ecg': {'description': 'Electrocardiogram signal.', 'rare': True, 'unit': '–'}, 'probe_pose': {'description': 'Sampled probe pose at the transducer tip.', 'rare': True, 'unit': '–'}, 'subject': {'description': 'Subject associated with the study.', 'unit': '–'}, 'text_report': {'description': 'Free-text report associated with the study.', 'rare': True, 'unit': '–'}, 'voice_narration': {'description': 'Voice narration signal.', 'rare': True, 'unit': '–'}}
annotations: Annotations | dict | None = None
credit: str | None = None
ecg: Signal1D | dict | None = None
probe_pose: ProbePose | dict | None = None
subject: Subject | dict | None
text_report: str | None = None
voice_narration: Signal1D | dict | None = None
class zea.data.spec.MetricsSpec(common_midpoint_phase_error=None, coherence_factor=None)[source]

Bases: Spec

Metrics group for acquisition-level quality/performance metrics.

Parameters:
  • common_midpoint_phase_error (ndarray | None) – Common midpoint phase error in radians of shape (n_frames,) and type float32.

  • coherence_factor (ndarray | None) – Coherence factor of shape (n_frames,) and type float32.

FIELD_METADATA: ClassVar[dict[str, Any]] = {'coherence_factor': {'description': 'Coherence factor; ratio of coherent to incoherent energy (0-1).', 'rare': True, 'unit': '–'}, 'common_midpoint_phase_error': {'description': 'Common midpoint phase error.', 'rare': True, 'unit': 'rad'}}
coherence_factor: ndarray | None = None
common_midpoint_phase_error: ndarray | None = None
class zea.data.spec.ProbePose(start_time_offset, translation, rotation, rotation_representation, *, sampling_frequency=None, timestamps=None)[source]

Bases: Signal

Sampled probe pose metadata at the tip of the transducer.

The pose uses the coordinate convention x = lateral along the transducer, y = elevation (out of plane), and z = axial (depth).

Parameters:
  • translation (ndarray) – Position of the transducer tip in meters of shape (T, 3), ordered as (x, y, z).

  • rotation (ndarray) – Orientation of the transducer tip of shape (T, 3) or (T, 4), interpreted according to rotation_representation.

  • rotation_representation (str) – Rotation parameterization. Supported values are "euler_xyz", "quaternion_wxyz", and "quaternion_xyzw".

  • start_time_offset (ndarray | float) – Time offset in seconds between the first transmit event of the ultrasound acquisition and sample 0 of this data.

  • sampling_frequency (ndarray | float | None) – Sampling frequency in Hz for probe pose samples.

  • timestamps (ndarray | None) – Explicit probe pose timestamps in seconds of shape (T,), relative to sample 0.

FIELD_METADATA: ClassVar[dict[str, Any]] = {'rotation': {'description': 'Orientation associated with the transducer-tip pose in the x-lateral, y-elevation, z-axial coordinate convention, interpreted according to rotation_representation.', 'unit': '–'}, 'rotation_representation': {'description': 'Rotation parameterization: one of euler_xyz, quaternion_wxyz, or quaternion_xyzw.', 'unit': '–'}, 'sampling_frequency': {'description': 'Sampling frequency.', 'unit': 'Hz'}, 'start_time_offset': {'description': 'Time offset between the first transmit event of the ultrasound acquisition and sample 0 of this data. Negative means this data starts before the first transmit event; positive means it starts after.', 'unit': 's'}, 'timestamps': {'description': 'Explicit sample timestamps relative to sample 0.', 'unit': 's'}, 'translation': {'description': 'Position of the transducer tip, ordered as (x, y, z), where x is lateral along the transducer, y is elevation (out of plane), and z is axial (depth).', 'unit': 'm'}}
rotation: ndarray
rotation_representation: str
translation: ndarray
class zea.data.spec.ProbeSpec(name=None, type=None, probe_center_frequency=None, probe_bandwidth_percent=None, probe_geometry=None, element_width=None, element_height=None, lens_sound_speed=None, lens_thickness=None)[source]

Bases: Spec

Probe hardware specification.

Stores static, physical characteristics of the transducer that are not captured by the per-acquisition ScanSpec. All fields are optional so that partial information can be recorded.

Parameters:
  • name (str | None) – Probe model identifier (e.g. "verasonics_l11_4v").

  • type (str | None) – Probe geometry type: "linear", "phased", "curved", etc.

  • probe_center_frequency (Union[float, int, floating, integer, None]) – Probe nominal centre frequency in Hz. Named distinctly from ScanSpec.center_frequency (the per-acquisition transmit frequency) so the two never collide when merged into a single zea.Parameters object.

  • probe_bandwidth_percent (Union[float, int, floating, integer, None]) – Fractional bandwidth as a percentage.

  • probe_geometry (ndarray | None) – Element positions in metres, shape (n_el, 3) with columns (x, y, z). n_el and pitch are computed automatically as read-only properties from this array.

  • element_width (Union[float, int, floating, integer, None]) – Width of a single transducer element in metres.

  • element_height (Union[float, int, floating, integer, None]) – Height (elevation aperture) of a single element in metres.

  • lens_sound_speed (Union[float, int, floating, integer, None]) – Speed of sound in the acoustic lens in m/s.

  • lens_thickness (Union[float, int, floating, integer, None]) – Thickness of the acoustic lens in metres.

FIELD_METADATA: ClassVar[dict[str, Any]] = {'element_height': {'description': 'Height (elevation aperture) of a single transducer element.', 'rare': True, 'unit': 'm'}, 'element_width': {'description': 'Width of a single transducer element.', 'unit': 'm'}, 'lens_sound_speed': {'description': 'Speed of sound in the acoustic lens.', 'rare': True, 'unit': 'm/s'}, 'lens_thickness': {'description': 'Thickness of the acoustic lens.', 'rare': True, 'unit': 'm'}, 'name': {'description': 'Probe model name/identifier.'}, 'probe_bandwidth_percent': {'description': 'Fractional bandwidth as a percentage.', 'unit': '%'}, 'probe_center_frequency': {'description': "Probe nominal centre frequency (midpoint of the probe's -6 dB band).", 'unit': 'Hz'}, 'probe_geometry': {'description': 'Element positions (x, y, z) per element, shape (n_el, 3).', 'unit': 'm'}, 'type': {'description': 'Probe geometry type (linear, phased, curved, ...).'}}
element_height: float | int | floating | integer | None = None
element_width: float | int | floating | integer | None = None
lens_sound_speed: float | int | floating | integer | None = None
lens_thickness: float | int | floating | integer | None = None
property n_el: int | None

Number of transducer elements, derived from probe_geometry.

name: str | None = None
probe_bandwidth_percent: float | int | floating | integer | None = None
probe_center_frequency: float | int | floating | integer | None = None
probe_geometry: ndarray | None = None
type: str | None = None
class zea.data.spec.ScanSpec(sampling_frequency, center_frequency, demodulation_frequency, initial_times, t0_delays, tx_apodizations, focus_distances, transmit_origins, polar_angles, time_to_next_transmit=None, azimuth_angles=None, sound_speed=None, tgc_gain_curve=None, waveforms_one_way=None, waveforms_two_way=None)[source]

Bases: Spec

Scan group with acquisition and transmit metadata.

All fields are aligned with the data format specification.

Parameters:
  • sampling_frequency (ndarray | float) – The sampling frequency in Hz.

  • center_frequency (ndarray[Any, dtype[Any]] | float) – The center frequency in Hz of the transmit pulse. Single scalar if all transmits share the same center frequency; otherwise an array of shape (n_tx,) with one frequency per transmit.

  • demodulation_frequency (ndarray[Any, dtype[Any]] | float) – The frequency in Hz at which the data should be demodulated. Usually the same as center_frequency, but different when doing harmonic imaging. Single scalar if all transmits share the same center frequency; otherwise an array of shape (n_tx,) with one frequency per transmit.

  • initial_times (ndarray) – The times in seconds when the A/D converter starts sampling of shape (n_tx,). This is the time between the first element firing and the first recorded sample.

  • t0_delays (ndarray) – The transmit delays in seconds for each element of shape (n_tx, n_el). This is the time at which each element fires, shifted such that the first element fires at t=0.

  • tx_apodizations (ndarray) – The apodization values that were applied to each element during transmit of shape (n_tx, n_el). This is a value between -1 and 1 that indicates how much each element contributed to the transmit beam, with 0 meaning no contribution and 1 meaning full contribution. Negative values indicate that the element was fired with opposite polarity.

  • focus_distances (ndarray) –

    The transmit focus distances in meters of shape (n_tx,). This is the distance from the transmit origin on the transducer to where the beam comes to focus. The sign and magnitude encode the transmit type:

    • positive finite: focused transmit; the beam focuses at this distance in front of the array.

    • negative finite: diverging transmit; the (virtual) source lies this distance behind the array.

    • infinite (np.inf): plane wave. This is the preferred, canonical value for plane waves in zea. 0.0 is also accepted as a plane-wave marker (e.g. raw Verasonics data stores 0), but new data should use np.inf.

    See zea.Parameters.find_transmits() for how these values are used to classify transmits as "focused", "diverging" or "plane".

  • transmit_origins (ndarray) – The transmit origins of the transmit beams in meters of shape (n_tx, 3). This is the (x, y, z) position from which the beam is transmitted.

  • polar_angles (ndarray) – The polar angles in radians of the transmit beams of shape (n_tx,).

  • time_to_next_transmit (ndarray | None) – The time in s between subsequent transmit events. Shape is either (n_frames, n_tx) or flat (n_frames * n_tx - 1,).

  • azimuth_angles (ndarray | None) – The azimuthal angles in radians of the transmit beams of shape (n_tx,).

  • sound_speed (ndarray | float | None) – The speed of sound in meters per second.

  • tgc_gain_curve (ndarray | None) – The time-gain-compensation that was applied to every sample in the raw_data of shape (n_ax,). Divide by this curve to undo the TGC.

  • waveforms_one_way (ndarray | None) – One-way waveforms of shape (n_tx, .) as simulated by the Verasonics system. This is the waveform after being filtered by the transducer bandwidth once.

  • waveforms_two_way (ndarray | None) – Two-way waveforms of shape (n_tx, .) as simulated by the Verasonics system. This is the waveform after being filtered by the transducer bandwidth twice.

FIELD_METADATA: ClassVar[dict[str, Any]] = {'azimuth_angles': {'description': 'Azimuthal angles of transmit beams.', 'unit': 'rad'}, 'center_frequency': {'description': 'Center frequency of the transmit pulse.', 'unit': 'Hz'}, 'demodulation_frequency': {'description': 'Demodulation frequency.', 'unit': 'Hz'}, 'focus_distances': {'description': 'Transmit focus distances. Positive = focused, negative = diverging (virtual source behind the array), ``np.inf`` = plane wave (preferred; ``0`` is also accepted).', 'unit': 'm'}, 'initial_times': {'description': 'A/D converter start times per transmit.', 'unit': 's'}, 'polar_angles': {'description': 'Polar angles of transmit beams.', 'unit': 'rad'}, 'sampling_frequency': {'description': 'Sampling frequency.', 'unit': 'Hz'}, 'sound_speed': {'description': 'Speed of sound.', 'unit': 'm/s'}, 't0_delays': {'description': 'Transmit delays per element.', 'unit': 's'}, 'tgc_gain_curve': {'description': 'Time-gain-compensation curve.', 'rare': True, 'unit': '–'}, 'time_to_next_transmit': {'description': 'Time between transmit events.', 'unit': 's'}, 'transmit_origins': {'description': 'Transmit beam origins (x, y, z).', 'unit': 'm'}, 'tx_apodizations': {'description': 'Transmit apodization per element, in [-1, 1]. 0 = element did not contribute, 1 = full contribution, negative = fired with opposite polarity.', 'unit': '–'}, 'waveforms_one_way': {'description': 'One-way transmit waveforms.', 'rare': True, 'unit': 'V'}, 'waveforms_two_way': {'description': 'Two-way transmit waveforms.', 'rare': True, 'unit': 'V'}}
azimuth_angles: ndarray | None = None
center_frequency: ndarray[Any, dtype[Any]] | float
demodulation_frequency: ndarray[Any, dtype[Any]] | float
focus_distances: ndarray
initial_times: ndarray
property n_el: int

Number of elements.

property n_tx: int

Number of transmits.

polar_angles: ndarray
sampling_frequency: ndarray | float
sound_speed: ndarray | float | None = None
t0_delays: ndarray
tgc_gain_curve: ndarray | None = None
time_to_next_transmit: ndarray | None = None
transmit_origins: ndarray
tx_apodizations: ndarray
waveforms_one_way: ndarray | None = None
waveforms_two_way: ndarray | None = None
class zea.data.spec.Segmentation(values, coordinates=None, timestamps=None, start_time_offset=None, labels=None, description=None, unit=None, min=None, max=None)[source]

Bases: BooleanMap

Segmentation data with per-pixel Cartesian coordinates.

Parameters:
  • values (ndarray) – The segmentation values of shape (n_frames, z, x, y, n_labels) for 3D (volumetric) data or (n_frames, z, x, n_labels) for 2D data, with type bool.

  • coordinates (ndarray | None) – Per-pixel Cartesian positions in metres, shape (*spatial_dims, 3) where spatial_dims matches the spatial (non-label) dimensions of values. The leading frame axis may be omitted to broadcast one coordinate grid across all frames.

  • labels (ndarray | None) – The labels corresponding to the segmentation values, where each unique value in the values corresponds to a label in this list of shape (n_labels,) and type str.

Note

To indicate that certain frames have no segmentation, add an explicit "unannotated" entry to labels and set values[..., unannotated_idx] to True for those frames (with all other label channels set to False). This keeps the shape uniform across frames while clearly distinguishing genuinely annotated frames from frames that were not labelled. For example:

labels = np.array(["unannotated", "LV_endo", "LV_myo", "LA"])
values = np.zeros((n_frames, H, W, 4), dtype=bool)
# mark all frames as unannotated by default
values[:, :, :, 0] = True
# for annotated frames, set unannotated channel to False
# and the appropriate label channel to True
values[ed_idx, :, :, 0] = False
values[ed_idx, :, :, 1:] = segmentation_mask  # shape (H, W, 3)
class zea.data.spec.ShearWaveElastographyMap(values, coordinates=None, timestamps=None, start_time_offset=None, labels=None, description=None, unit=None, min=None, max=None)[source]

Bases: FloatMap

Shear-wave elastography data with per-pixel Cartesian coordinates.

Parameters:
  • values (ndarray) – The shear-wave elastography values in m/s of shape (n_frames, z, x, y) and type float32.

  • coordinates (ndarray | None) – Per-pixel Cartesian positions in metres.

class zea.data.spec.Signal(start_time_offset, *, sampling_frequency=None, timestamps=None)[source]

Bases: Spec

Base class for additional signals with timing metadata.

Parameters:
  • start_time_offset (ndarray | float) – Time offset in seconds between the first transmit event of the ultrasound acquisition and sample 0 of this data. Negative means this data starts before the first transmit event; positive means it starts after.

  • sampling_frequency (ndarray | float | None) – Sampling frequency in Hz for uniformly sampled data.

  • timestamps (ndarray | None) – Explicit sample timestamps in seconds of shape (T,), relative to sample 0. Must start at 0.

Exactly one of sampling_frequency or timestamps must be provided.

FIELD_METADATA: ClassVar[dict[str, Any]] = {'sampling_frequency': {'description': 'Sampling frequency.', 'unit': 'Hz'}, 'start_time_offset': {'description': 'Time offset between the first transmit event of the ultrasound acquisition and sample 0 of this data. Negative means this data starts before the first transmit event; positive means it starts after.', 'unit': 's'}, 'timestamps': {'description': 'Explicit sample timestamps relative to sample 0.', 'unit': 's'}}
sampling_frequency: ndarray | float | None = None
start_time_offset: ndarray | float
timestamps: ndarray | None = None
class zea.data.spec.Signal1D(start_time_offset, samples, *, sampling_frequency=None, timestamps=None)[source]

Bases: Signal

One-dimensional sampled signal with timing metadata.

Parameters:
  • samples (ndarray) – Signal samples of shape (T) and type uint8 or float32 or int16 or complex64.

  • start_time_offset (ndarray | float) – Time offset in seconds between the first transmit event of the ultrasound acquisition and sample 0 of this data.

  • sampling_frequency (ndarray | float | None) – Sampling frequency in Hz for signal samples.

  • timestamps (ndarray | None) – Explicit signal timestamps in seconds of shape (T,), relative to sample 0.

Exactly one of sampling_frequency or timestamps must be provided.

FIELD_METADATA: ClassVar[dict[str, Any]] = {'samples': {'description': 'Signal samples.', 'unit': '–'}, 'sampling_frequency': {'description': 'Sampling frequency.', 'unit': 'Hz'}, 'start_time_offset': {'description': 'Time offset between the first transmit event of the ultrasound acquisition and sample 0 of this data. Negative means this data starts before the first transmit event; positive means it starts after.', 'unit': 's'}, 'timestamps': {'description': 'Explicit sample timestamps relative to sample 0.', 'unit': 's'}}
samples: ndarray
class zea.data.spec.SignalND(start_time_offset, samples, *, sampling_frequency=None, timestamps=None)[source]

Bases: Signal

N-dimensional sampled signal with timing metadata.

Parameters:
  • samples (ndarray) – Signal samples of shape (T, …) and type uint8 or float32 or int16 or complex64.

  • start_time_offset (ndarray | float) – Time offset in seconds between the first transmit event of the ultrasound acquisition and sample 0 of this data.

  • sampling_frequency (ndarray | float | None) – Sampling frequency in Hz for signal samples.

  • timestamps (ndarray | None) – Explicit signal timestamps in seconds of shape (T,), relative to sample 0.

Exactly one of sampling_frequency or timestamps must be provided.

FIELD_METADATA: ClassVar[dict[str, Any]] = {'samples': {'description': 'Signal samples.', 'unit': '–'}, 'sampling_frequency': {'description': 'Sampling frequency.', 'unit': 'Hz'}, 'start_time_offset': {'description': 'Time offset between the first transmit event of the ultrasound acquisition and sample 0 of this data. Negative means this data starts before the first transmit event; positive means it starts after.', 'unit': 's'}, 'timestamps': {'description': 'Explicit sample timestamps relative to sample 0.', 'unit': 's'}}
samples: ndarray
class zea.data.spec.SosMap(values, coordinates=None, timestamps=None, start_time_offset=None, labels=None, description=None, unit=None, min=None, max=None)[source]

Bases: FloatMap

Speed-of-sound map data with per-pixel Cartesian coordinates.

Parameters:
  • values (ndarray) – The speed-of-sound map values in m/s of shape (n_frames, z, x, y) and type float32.

  • coordinates (ndarray | None) – Per-pixel Cartesian positions in metres, shape (n_frames, z, x, 3) or (n_frames, z, x, y, 3). The leading frame axis may be omitted to broadcast one coordinate grid across all frames.

class zea.data.spec.Spec[source]

Bases: object

Base class for data specifications with schema validation.

Subclasses should define a SCHEMA class variable that specifies the expected dtype and shape for each field. The __post_init__ method will validate that the actual fields match the schema, including checking that dimensions with the same name have consistent sizes across fields.

FIELD_METADATA: ClassVar[dict[str, Any]]
static create_dataset(group, field_name, value, compression=Blosc(cname='zstd', clevel=7, shuffle=2), chunk_axes=('n_frames',), dim_names=None)[source]

Create a dataset in the given group for the specified field and value, handling string and scalar values appropriately.

compression may be an h5py filter name (e.g. "lzf", "gzip") or a mapping of create_dataset keyword arguments, such as an hdf5plugin filter object (hdf5plugin.Blosc2(...)) or an explicit {"compression": "gzip", "compression_opts": 4}. Reading such a file back requires the corresponding filter to be available (for hdf5plugin filters, import hdf5plugin in the reading process).

When dim_names (the field’s schema dimension names) is provided, the chunk shape is derived from chunk_axes to match common subsampling patterns; see _resolve_chunks().

Return type:

None

classmethod fields()[source]

Return the names of all fields.

Return type:

tuple[str, ...]

classmethod get_dtype(field_name)[source]

Get the dtype of a field.

Return type:

Union[Tuple[type, ...], type]

classmethod optional_fields()[source]

Return the names of fields that have a default value.

Return type:

tuple[str, ...]

classmethod required_fields()[source]

Return the names of fields that have no default value.

Return type:

tuple[str, ...]

store_in_group(group, compression=Blosc(cname='zstd', clevel=7, shuffle=2), chunk_axes=('n_frames',), warn_missing_optional_fields=True)[source]

Store the data in the given group (e.g. hdf5 group).

Return type:

None

to_dict()[source]

Return this spec as a nested dictionary based on SCHEMA fields.

Nested specs are converted recursively.

Return type:

dict[str, Any]

warn_missing_optional_fields()[source]

Warn about optional fields that were not provided.

Fields flagged as "rare" in FIELD_METADATA are skipped: they are almost never set, so warning about them on every write is just noise.

class zea.data.spec.StrainPercentageMap(values, coordinates=None, timestamps=None, start_time_offset=None, labels=None, description=None, unit=None, min=None, max=None)[source]

Bases: FloatMap

Strain map data with per-pixel Cartesian coordinates.

Parameters:
  • values (ndarray) – The strain values in % of shape (n_frames, z, x, y) and type float32.

  • coordinates (ndarray | None) – Per-pixel Cartesian positions in metres.

class zea.data.spec.Subject(id=None, type=None, age=None, sex=None, weight=None, genetic_strain=None, fat_percentage=None, bmi=None)[source]

Bases: Spec

Subject metadata associated with the study.

Parameters:
  • id (str | None) – Subject ID.

  • type (str | None) – Subject type, e.g. human, phantom, animal.

  • age (uint8 | None) – Subject age in years.

  • sex (str | None) – Subject sex.

  • weight (float32 | None) – Subject weight in kg.

  • genetic_strain (str | None) – Genetic strain of an animal subject, e.g. C57BL/6N.

  • fat_percentage (float32 | None) – Subject fat percentage.

  • bmi (float32 | None) – Subject body mass index in kg/m².

FIELD_METADATA: ClassVar[dict[str, Any]] = {'age': {'description': 'Subject age in years.', 'rare': True, 'unit': '–'}, 'bmi': {'description': 'Subject body mass index.', 'rare': True, 'unit': 'kg/m²'}, 'fat_percentage': {'description': 'Subject fat percentage.', 'rare': True, 'unit': '%'}, 'genetic_strain': {'description': 'Genetic strain (inbred line) of an animal subject, e.g. C57BL/6N.', 'rare': True, 'unit': '–'}, 'id': {'description': 'Subject ID. Needed for subject-wise splits.', 'unit': '–'}, 'sex': {'description': 'Subject sex.', 'rare': True, 'unit': '–'}, 'type': {'description': 'Subject type, e.g. human, phantom, animal.', 'unit': '–'}, 'weight': {'description': 'Subject weight.', 'rare': True, 'unit': 'kg'}}
age: uint8 | None = None
bmi: float32 | None = None
fat_percentage: float32 | None = None
genetic_strain: str | None = None
id: str | None = None
sex: str | None = None
type: str | None = None
weight: float32 | None = None
class zea.data.spec.TissueDopplerMap(values, coordinates=None, timestamps=None, start_time_offset=None, labels=None, description=None, unit=None, min=None, max=None)[source]

Bases: FloatMap

Tissue Doppler data with per-pixel Cartesian coordinates.

Parameters:
  • values (ndarray) – The tissue Doppler values in m/s of shape (n_frames, z, x, y) and type float32.

  • coordinates (ndarray | None) – Per-pixel Cartesian positions in metres.

class zea.data.spec.TrackSpec(data=None, scan=None, label=None, transmit_only=False)[source]

Bases: Spec

A single acquisition track with its own data and scan parameters.

Used inside a multi-track FileSpec where different transmit sequences coexist in the same acquisition. The track_schedule on FileSpec specifies the global ordering of transmits across all tracks.

For multi-track files a human-readable label is required on every track so that users can identify which track is which (e.g. "focused" vs "planewave"). Further information can be provided in the description field of the parent FileSpec, if necessary. Single-track files may omit the label.

A track must carry at least one of data or scan. data may be left as None to describe a transmit-only track (one that records the transmit sequence via scan but stores no recorded data), but only when scan is provided and transmit_only=True is explicitly passed.

A transmit-only track is useful when we want to store information about a transmit event without any corresponding receive data, for example a shear wave push pulse or therapeutic ultrasound.

Parameters:
  • data (DataSpec | dict | None) – The data for this track. May be None for a transmit-only track (e.g. to store a shear wave push pulse), but only if scan is provided and transmit_only=True.

  • scan (ScanSpec | dict | None) – The scan parameters for this track. Required when raw_data is present in data, and required when data is None.

  • label (str | None) – Short human-readable name for this track (e.g. "focused" or "planewave"). Required when the parent FileSpec contains more than one track.

  • transmit_only (bool) – Must be explicitly set to True to construct a transmit-only track (data=None with scan provided).

FIELD_METADATA: ClassVar[dict[str, Any]] = {'data': {'description': 'Recorded data for this track; may be omitted for a transmit-only track.', 'unit': '–'}, 'label': {'description': 'Short human-readable track name.', 'rare': True, 'unit': '–'}, 'scan': {'description': 'Scan acquisition parameters for this track; required when raw_data is present in data, or when data is omitted.', 'unit': '–'}, 'transmit_only': {'description': 'Whether this track records only the transmit sequence with no corresponding receive data (e.g. a shear wave push pulse or therapeutic ultrasound).', 'rare': True, 'unit': '–'}}
data: DataSpec | dict | None = None
label: str | None = None
scan: ScanSpec | dict | None = None
store_in_group(group, compression=Blosc(cname='zstd', clevel=7, shuffle=2), chunk_axes=('n_frames',), warn_missing_optional_fields=True)[source]

Store data, scan, and label in the HDF5 group.

Return type:

None

transmit_only: bool = False
class zea.data.spec.UnsignedIntMap(values, coordinates=None, timestamps=None, start_time_offset=None, labels=None, description=None, unit=None, min=None, max=None)[source]

Bases: Map

Map data with uint8 pixel values and per-pixel Cartesian coordinates.

zea.data.spec.check_dtype(value, expected_dtype)[source]

Check if the dtype of a value matches the expected dtype, allowing for compatible types.

Works for numpy arrays, numpy scalars, and Python native types.

Return type:

None

zea.data.spec.find_matched_shape(value, expected_shapes)[source]

Find the first expected shape specification that matches the shape of the value.

Return type:

tuple | None

zea.data.spec.match_shape(value, expected_shape)[source]

Check if the shape of a value matches the expected shape specification.

Return type:

bool

zea.data.spec.value_shape(value)[source]

Return the shape tuple for numpy arrays and scalar values.

Return type:

tuple