RegularTimeSeries#

class temporaldata.RegularTimeSeries(*, sampling_rate, domain_start=0.0, **kwargs)[source]#

Bases: ArrayDict

A regular time series is the same as an irregular time series, but it has a regular sampling rate. This allows for faster indexing, possibility of patching data and meaningful Fourier operations. The first dimension of all attributes must be the time dimension.

Note

If you have a matrix of shape \((N, T)\), where \(N\) is the number of channels and \(T\) is the number of time points, you should transpose it to \((T, N)\) before passing it to the constructor, since the first dimension should always be time.

Parameters:
  • sampling_rate (float) – Sampling rate in Hz.

  • domain_start (float) – Absolute starting time offset (in seconds) of this signal. Defaults to 0.0.

  • **kwargs (ndarray | list | tuple | _SupportsArray) – Arbitrary keyword arguments where the values are arbitrary multi-dimensional (2d, 3d, …, nd) arrays with shape (N, *).

See also

from_gappy_timeseries() to construct from regular timeseries that has gaps or missing values.

Example

>>> import numpy as np
>>> from temporaldata import RegularTimeSeries

>>> lfp = RegularTimeSeries(
...     raw=np.zeros((1000, 128)),
...     sampling_rate=250.,
... )

>>> lfp.slice(0, 1)
RegularTimeSeries(
  raw=[250, 128]
)

>>> lfp.to_irregular()
IrregularTimeSeries(
  timestamps=[1000],
  raw=[1000, 128]
)
property sampling_rate: float#

Sampling rate in Hz

property timestamps: ndarray#

Sample timestamps

property domain: Interval#

Domain of this time series

index_mask()[source]#

Boolean mask marking which samples fall inside domain.

For a gappy RegularTimeSeries (one whose domain consists of more than one interval), some positions along the time axis are fill values rather than real observations. This method returns a 1-D boolean array of length len(self) where True marks a real sample and False marks a gap (fill).

For a contiguous RegularTimeSeries (single-interval domain) the result is all True.

Returns:

1-D boolean array of shape (len(self),).

Return type:

np.ndarray

Example

>>> import numpy as np
>>> from temporaldata import RegularTimeSeries

>>> # Contiguous (non-gappy) series: every sample is real.
>>> rts = RegularTimeSeries(
...     raw=np.arange(4), sampling_rate=100.0,
... )
>>> rts.index_mask()
array([ True,  True,  True,  True])

>>> # Gappy series: 0.02s and 0.05s samples are missing.
>>> ts = [0.0, 0.01, 0.03, 0.04, 0.06]
>>> raw = [1, 2, 3, 4, 5]
>>> rts = RegularTimeSeries.from_gappy_timeseries(
...     ts, sampling_rate=100.0, raw=raw,
... )
>>> rts.index_mask()
array([ True,  True, False,  True,  True, False,  True])
>>> rts.raw  # contains fill values
array([ 1,  2, -1,  3,  4, -1,  5])
>>> rts.raw[rts.index_mask()]
array([1, 2, 3, 4, 5])
select_by_mask(mask)[source]#

Raises a NotImplementedError as this method is not supported for RegularTimeSeries.

Raises:

NotImplementedError – Always, because this method cannot be implemented for this class.

slice(start, end, reset_origin=True, eps=1e-09)[source]#

Returns a new RegularTimeSeries object that contains the data between the start (inclusive) and end (exclusive) times (i.e., [start, end)).

start and end are snapped up to the next grid point (the next multiple of 1/sampling_rate).

  • Gap-filled samples at the start or end of the result are trimmed, so returned data always begins and ends on real samples.

  • Gaps in the middle of the window are preserved as-is and remain filled with the gap value.

  • Slices that fall fully outside the domain or entirely within a gap return empty data.

Parameters:
  • start (float) – Start time.

  • end (float) – End time.

  • reset_origin (bool) – If True, all time attributes will be updated to be relative to the new start time. Defaults to True.

  • eps (float) – A tiny ‘rounding buffer’ to handle floating-point noise when computing indices. If your sampling rate is very high, you may need to increase this (e.g., to 1e-7) to avoid off-by-one errors.

Returns:

A new instance of the same class containing a subset of the data. The new object will have a modified Interval domain reflecting the actual sampled boundaries.

Return type:

RegularTimeSeries

to_irregular()[source]#

Converts the RegularTimeSeries object to an IrregularTimeSeries object.

Gap-fill samples (where index_mask() is False) are dropped.

The returned arrays (timestamps, values, and domain) are independent copies; mutating them will not affect this RegularTimeSeries.

Returns:

IrregularTimeSeries with timestamps and all attributes copied.

Example

>>> import numpy as np
>>> from temporaldata import RegularTimeSeries

>>> # Contiguous (non-gappy) series: every sample is kept.
>>> rts = RegularTimeSeries(raw=np.arange(4), sampling_rate=10.0)
>>> irts = rts.to_irregular()
>>> irts.timestamps
array([0. , 0.1, 0.2, 0.3])
>>> irts.raw
array([0, 1, 2, 3])

>>> # Gappy series: gap-fill samples are dropped.
>>> ts = [0.0, 0.01, 0.03, 0.04, 0.06]
>>> raw = [1, 2, 3, 4, 5]
>>> rts = RegularTimeSeries.from_gappy_timeseries(
...     ts, sampling_rate=100.0, raw=raw,
... )
>>> rts.raw  # contains fill values
array([ 1,  2, -1,  3,  4, -1,  5])
>>> irts = rts.to_irregular()
>>> irts.timestamps
array([0.  , 0.01, 0.03, 0.04, 0.06])
>>> irts.raw
array([1, 2, 3, 4, 5])
to_hdf5(file)[source]#

Saves the data object to an HDF5 file.

Parameters:

file (h5py.File) – HDF5 file.

import h5py
from temporaldata import RegularTimeSeries

data = RegularTimeSeries(
    raw=np.zeros((1000, 128)),
    sampling_rate=250.,
)

with h5py.File("data.h5", "w") as f:
    data.to_hdf5(f)
classmethod from_hdf5(file)[source]#

Loads the data object from an HDF5 file.

Parameters:

file (h5py.File) – HDF5 file.

Note

This method will load all data in memory, if you would like to use lazy loading, call LazyRegularTimeSeries.from_hdf5() instead.

import h5py
from temporaldata import RegularTimeSeries

with h5py.File("data.h5", "r") as f:
    data = RegularTimeSeries.from_hdf5(f)
classmethod from_gappy_timeseries(timestamps, sampling_rate, gap_value=None, rtol=0.001, **kwargs)[source]#

Regularize an approximately-regular but gappy timeseries.

Construct a RegularTimeSeries from approximately-regular but gappy timestamps and value arrays by snapping each sample to a regular grid at sampling_rate and filling missing samples with gap_value.

Useful for signals that are nominally regular (e.g. behavioral streams at a fixed sampling rate) but contain missing samples, which would otherwise have to be carried as an IrregularTimeSeries and would suffer numerical-precision issues during slicing.

Parameters:
  • timestamps (ndarray | list | tuple | _SupportsArray) – 1-D array-like of timestamps, strictly increasing. Each entry must lie within rtol samples of a regular grid at sampling_rate, anchored at timestamps[0].

  • sampling_rate (float) – Sampling rate in Hz.

  • gap_value (Union[Any, dict[str, Any], None]) –

    Value used to fill missing samples. May be:

    • None (default) — uses per-kind defaults: -1 for signed integers, 0 for unsigned integers, numpy.nan for floats, False for bools.

    • A scalar (int, float, or bool) — used for every kwarg array regardless of dtype.

    • A dict mapping numpy.dtype.kind codes to fill values. Recognized kinds: 'b' (bool), 'i' (signed int), 'u' (unsigned int), 'f' (float). Example: {'i': -1, 'u': 0, 'f': np.nan}. Raises KeyError if a kwarg’s dtype kind is not in the dict.

  • rtol (float) – Maximum allowed deviation, in samples, of any input timestamp from the regular grid.

  • **kwargs (ndarray | list | tuple | _SupportsArray) – Named array-like values whose first dimension equals len(timestamps).

Returns:

A regular time series with the same named arrays, gaps filled with gap_value.

Return type:

RegularTimeSeries

Raises:

ValueError – If timestamps deviate from the regular grid by more than rtol

See also

  • is_gappy() to check whether a series has gaps.

  • index_mask() for a boolean mask of real vs. gap-fill samples.

Example

>>> import numpy as np
>>> from temporaldata import RegularTimeSeries

>>> # 4 samples at 100 Hz, the 0.02s sample is missing.
>>> ts = np.array([0.0, 0.01, 0.03, 0.04])
>>> raw = np.array([1.0, 2.0, 3.0, 4.0])
>>> rts = RegularTimeSeries.from_gappy_timeseries(
...     ts, sampling_rate=100.0, raw=raw,
... )
>>> rts.raw
array([ 1.,  2., nan,  3.,  4.])
>>> rts.domain.start
array([0.  , 0.03])
>>> rts.domain.end
array([0.02, 0.05])
>>> rts.index_mask()  # indicates valid and filled-in timestamps
array([ True,  True, False,  True,  True])
is_gappy()[source]#

Returns True if this RegularTimeSeries has gaps.

A series is gappy when its domain is made up of more than one interval; positions inside the gaps are filled with the configured gap value (see from_gappy_timeseries()). A contiguous series (single-interval domain) returns False.

Returns:

True if the domain has more than one interval.

Return type:

bool

See also

index_mask() for a boolean mask of real vs. gap-fill samples.

Example

>>> import numpy as np
>>> from temporaldata import RegularTimeSeries

>>> rts = RegularTimeSeries(raw=np.arange(4), sampling_rate=100.0)
>>> rts.is_gappy()
False

>>> rts = RegularTimeSeries.from_gappy_timeseries(
...     [0.0, 0.01, 0.03], sampling_rate=100.0, raw=[1, 2, 3],
... )
>>> rts.is_gappy()
True
classmethod from_dataframe(df, unsigned_to_long=True, **kwargs)#

Creates an ArrayDict object from a pandas DataFrame.

The columns in the DataFrame are converted to arrays when possible, otherwise they will be skipped.

Parameters:
  • df (pandas.DataFrame) – DataFrame.

  • unsigned_to_long (bool, optional) – If True, automatically converts unsigned integers to int64. Defaults to True.

keys()#

Returns a list of all array attribute names.

Return type:

List[str]

materialize()#

Materializes the data object, i.e., loads into memory all of the data that is still referenced in the HDF5 file.

Return type:

ArrayDict