Metadata-Version: 2.4
Name: timeseries-zarr
Version: 0.1.0a4
Summary: Produces Zarr v3 viewer bundles from neurophysiology time series
Author: Rohan Shah
License-Expression: Apache-2.0
Project-URL: Source, https://github.com/Pennsieve/timeseries-zarr-py
Project-URL: Issues, https://github.com/Pennsieve/timeseries-zarr-py/issues
Project-URL: Specification, https://github.com/Pennsieve/timeseries-zarr-py/blob/main/docs/spec.md
Project-URL: Changelog, https://github.com/Pennsieve/timeseries-zarr-py/blob/main/CHANGELOG.md
Keywords: zarr,time series,neurophysiology,electrophysiology,downsampling,pyramid
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: zarr<4,>=3
Requires-Dist: numpy>=1.26
Provides-Extra: test
Requires-Dist: pytest>=7.0.0; extra == "test"
Requires-Dist: pytest-cov>=4.0.0; extra == "test"
Requires-Dist: pytest-mock>=3.10.0; extra == "test"
Provides-Extra: dev
Requires-Dist: mypy>=1.8.0; extra == "dev"
Requires-Dist: ruff==0.17.0; extra == "dev"
Requires-Dist: pre-commit; extra == "dev"
Dynamic: license-file

# timeseries-zarr-py

Python library and reference implementation for the
[TS-Zarr specification](https://github.com/Pennsieve/timeseries-zarr-py/blob/main/docs/spec.md).

## Installation

Requires Python 3.12 or later. The runtime dependencies are `zarr>=3` and `numpy`.

```bash
pip install timeseries-zarr
```

## Usage

`write_bundle` reads channel sources, computes per-bin statistics up
to the specified maximum number of levels of time resolution, and writes the
bundle to disk.

Each source implements `ContinuousChannelSource` or `EventChannelSource`, which
[`timeseries_zarr.protocols`](https://github.com/Pennsieve/timeseries-zarr-py/blob/main/timeseries_zarr/protocols.py)
defines.

This example writes a single channel holding a minute of a 10 Hz sine sampled at 1000 Hz:

```python
from pathlib import Path

import numpy as np

from timeseries_zarr import WriteOpts, write_bundle


class SineSource:
    id = "sine-0"
    name = "sine"
    unit = "uV"

    def __init__(self):
        t = np.arange(60_000) / 1000.0
        self._samples = (100.0 * np.sin(2 * np.pi * 10 * t)).astype(np.float32)

    def provenance(self):
        return {"software": "sine-example 1.0"}

    def rate_hz(self):
        return 1000.0

    def start_us(self):
        return 0

    def num_samples(self):
        return self._samples.shape[0]

    def read_samples(self, start, stop):
        return self._samples[start:stop]


write_bundle(
    [SineSource()],
    [],
    output_path=Path("sine.zarr"),
    opts=WriteOpts(),
)
```

Passing a `RecordingMeta` as `recording` adds a `recording.json` with the session
start time and subject, session, and source details. Every field is optional. A
`start` must be a timezone-aware `datetime`. Without one, `recording.json` holds no
date. The
[recording metadata](https://github.com/Pennsieve/timeseries-zarr-py/blob/main/docs/spec.md#recording-metadata)
section of the specification lists what the file can hold.

Sources must provide times in microseconds since the Unix epoch.
The writer stores them as offsets from the earliest start time in the recording.

`WriteOpts` fields:

| Field | Description | Default |
|---|---|---|
| `zstd_level` | Zstd compression level | 5 |
| `max_levels` | maximum number of levels; 0 writes raw samples only | 15 |
| `min_bins` | fewest bins a level may hold | 1024 |
| `inner_len` | inner Zarr chunk length in samples | 8192 |
| `target_shard_bytes` | target outer shard size in bytes | 16 MiB |
| `write_var` | include per-bin variance | `False` |
| `voltage_policy` | `"convert"` or `"require_uv"` | `"convert"` |

`max_levels=0` writes only raw samples, without pyramid levels or statistics.

`write_var=True` uses more memory. The writer holds one shard of statistics per level
while it writes.

`voltage_policy` specifies whether the writer should convert voltage channels to
microvolts and label them `uV` or raise `ValueError` for voltage channels not
already in `uV`. `timeseries_zarr.UNIT_TO_UV` maps each unit name treated as a voltage
unit to its factor to microvolts. All other units are stored as given.

## Development

```bash
make venv        # create the virtualenv and install the package with its extras
source venv/bin/activate

make test        # pytest
make typecheck   # mypy --strict
make lint        # ruff check --fix + ruff format (rewrites files)
make check       # ruff check + format check + mypy + pytest
make pre-commit  # install the git pre-commit hook
```

[Releasing](https://github.com/Pennsieve/timeseries-zarr-py/blob/main/docs/releasing.md)
describes how to publish a release.

## Related projects

- [timeseries-zarr-nwb](https://github.com/Pennsieve/timeseries-zarr-nwb) uses this
  library to convert NWB recordings to TS-Zarr bundles.
- [`@pennsieve/timeseries-zarr-reader`](https://github.com/Pennsieve/timeseries-zarr-reader)
  is a TypeScript implementation of a TS-Zarr bundle reader.

## License

Apache-2.0. See [LICENSE](https://github.com/Pennsieve/timeseries-zarr-py/blob/main/LICENSE).
