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.