spool_to_xarray

function of dascore.xarray.spool source

spool_to_xarray(
    spool: Spool ,
    dim: str = time,
    group: str | Sequence[str] | None = None,
    tolerance = 1.5,
    conflict: Literal[‘drop’, ‘raise’, ‘keep_first’] = raise,
    block_size: str | int | None[str, int, None] = None,
)

Convert a spool to a lazy, dask-backed xarray DataTree.

Patches are partitioned exactly as chunk partitions them: one tree node per group of related patches, holding one child node per merged output (segment_0 onward, ordered along dim), each with a dask-backed data variable. Node names follow the spool’s own naming rule — the one its repr’s tracks and a coverage plot’s lanes use. Building the tree reads no patch data — every shape, dtype, and coordinate comes from the spool’s metadata — and computing a selection loads only the source patches it touches.

Parameters

Parameter Description
spool The spool to convert.
dim The dimension segments are merged along.
group Attributes which partition patches into unrelated groups, exactly
as chunk uses them. Defaults to the config’s patch_kind_attrs.
tolerance The continuity tolerance deciding when a gap splits segments, as
in chunk (not the sampling-step grouping tolerance).
conflict How attribute conflicts within a segment resolve, as in chunk.
block_size The most a single dask block may hold, as a byte count or a
string dask parses (“256MiB”, “1GB”). This bounds a bulk read:
computing a whole segment asks for one block at a time, so a
source patch bigger than this is read in several windows along
dim rather than whole. It does not affect a selection, which
reads only what it asks for whatever the blocks are. None takes
the configured xarray_block_size (256 MiB by default); zero
makes each source patch one block. A patch whose format cannot
hand back a window (see FiberIO.read_array) stays one block
whatever this says: splitting it would read the file once per
block instead of once.
Note

A selection reads only the samples it names: the arrays are backed by a source spanning each segment, and dask fuses the selection into that source’s own read, which asks each member for its part of the window and no other member at all.

Requires xarray and dask. Coordinates associated with a dimension (rather than defining one) are not carried into the tree, and coordinates are rebuilt from their indexed envelopes, whose numeric values are floats — an integer-valued dimension coordinate comes back as floats.

The merged dimension’s coordinate, when it is a range or segmented, is served lazily by dascore.xarray.index.CoordIndex: its labels are computed on demand from the merged coordinate rather than stored, so an arbitrarily long merged time coordinate costs nothing to build, even when sub-tolerance gaps or slightly different sampling steps leave it segmented rather than one range. Label selection on it answers as Patch.sel does, and reading .values or asking for the pandas index materializes labels on demand. Other dimensions keep materialized labels, which per-channel arrays (gains, offsets) align with. xarray aligns a lazy index only with lazy ones: to combine a segment with arrays indexed along the merged dimension, or reindex it, give it an ordinary index first, which reads all its labels into memory (so select first where possible), e.g. data.drop_indexes("time").set_xindex("time"), or give the other array this index type, other.drop_indexes("time").set_xindex("time", CoordIndex), which reads no lazy labels where the two agree.

A spool with pending value-range selections cannot be converted: the catalog states such bounds as candidacy rather than sample positions, so the arrays cannot be sized without reading. Convert first and select on the tree (e.g. sel(time=...)), or select with samples=True on dimensions, which stays exact. Pending inventory enrichment is likewise refused, since the tree would omit the enriched attributes.