Skip to content

Working with Series Blocks

arrakis.block.SeriesBlock is the core data container in arrakis. It holds timeseries data for one or more channels at a given timestamp.

SeriesBlock

A SeriesBlock is returned by arrakis.api.fetch and yielded by arrakis.api.stream. It behaves like a read-only dictionary:

block = arrakis.fetch(channels, start, end)

# dictionary-like access
series = block["H1:CAL-DELTAL_EXTERNAL_DQ"]

# iterate
for channel, series in block.items():
    print(channel, series.data.shape)

# keys and length
print(list(block.keys()))
print(len(block))

Block-level properties:

Property Type Description
time float Start time in GPS seconds
t0 float Alias for time
time_ns int Start time in nanoseconds
duration float Duration in seconds
duration_ns int Duration in nanoseconds
end_ns int End time in nanoseconds

Series

Indexing a SeriesBlock by channel name returns a arrakis.block.Series -- a single-channel timeseries with metadata:

series = block["H1:CAL-DELTAL_EXTERNAL_DQ"]

series.data         # numpy.ndarray (or numpy.ma.MaskedArray for gaps)
series.sample_rate  # Hz
series.time         # GPS start time in seconds
series.duration     # seconds
series.dt           # time step between samples (1 / sample_rate)
series.times        # array of GPS timestamps for each sample
series.name         # channel name
series.data_type    # numpy dtype of data
series.has_nulls    # True if data contains masked (gap) values

Filtering

Use filter() to create a new block with a subset of channels:

filtered = block.filter(["H1:CAL-DELTAL_EXTERNAL_DQ"])
print(list(filtered.keys()))  # ["H1:CAL-DELTAL_EXTERNAL_DQ"]

Concatenating Blocks

arrakis.block.concatenate_blocks joins time-sequential blocks into a single block. The blocks must be contiguous in time and contain the same channels:

from arrakis.block import concatenate_blocks

blocks = list(arrakis.stream(channels, start, end))
combined = concatenate_blocks(*blocks)

print(combined.time)      # start time of first block
print(combined.duration)  # total duration

This is what fetch() does internally.

Combining Blocks

arrakis.block.combine_blocks merges blocks from the same timestamp that contain different channels into a single block:

from arrakis.block import combine_blocks

# block_a has channels A and B, block_b has channels C and D
# both have the same time and duration
merged = combine_blocks(block_a, block_b)
print(list(merged.keys()))  # channels A, B, C, D

All blocks must have the same time_ns and duration_ns.

Gap Handling

Gaps in the data are represented as NumPy masked arrays (numpy.ma.MaskedArray) with all values masked.

Detecting gaps

for channel, series in block.items():
    if series.has_nulls:
        print(f"{channel}: contains gaps")

Creating gap blocks

Create a block where all channels are gaps:

from arrakis import Time
from arrakis.block import SeriesBlock

gap_block = SeriesBlock.full_gap(
    time_ns=1187000000 * Time.SECONDS,
    duration_ns=1 * Time.SECONDS,
    channels=metadata.values(),  # iterable of Channel objects
)

Add gap channels to an existing block for channels that are missing:

block_with_gaps = block.create_gaps(all_channels)

This fills in any channels from all_channels that are not already present in the block with masked arrays.