Metadata-Version: 2.4
Name: ecg-records
Version: 0.1.0
Summary: Versioned ECG Record extraction, measurement and plotting (research and engineering software; not a medical device)
Author: humansys-lab
Maintainer: humansys-lab
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/humansys-lab/ECG-feature-extraction-
Project-URL: Repository, https://github.com/humansys-lab/ECG-feature-extraction-
Project-URL: Issues, https://github.com/humansys-lab/ECG-feature-extraction-/issues
Project-URL: Documentation, https://github.com/humansys-lab/ECG-feature-extraction-/tree/main/docs/site
Project-URL: Changelog, https://github.com/humansys-lab/ECG-feature-extraction-/blob/main/feature_extraction/CHANGELOG.md
Keywords: ecg,electrocardiography,signal-processing,delineation,physionet,visualization
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Classifier: Topic :: Scientific/Engineering :: Visualization
Classifier: Typing :: Typed
Requires-Python: <3.14,>=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: numpy<3,>=1.26
Requires-Dist: scipy<2,>=1.11
Provides-Extra: viz
Requires-Dist: matplotlib<4,>=3.7; extra == "viz"
Provides-Extra: interpret
Requires-Dist: ecginterpret<1,>=0.1; extra == "interpret"
Provides-Extra: performance
Requires-Dist: numba<0.67,>=0.59; extra == "performance"
Provides-Extra: wfdb
Requires-Dist: wfdb<5,>=4.1; extra == "wfdb"
Provides-Extra: dev
Requires-Dist: build<2,>=1.2; extra == "dev"
Requires-Dist: hypothesis<7,>=6.100; extra == "dev"
Requires-Dist: import-linter<3,>=2; extra == "dev"
Requires-Dist: jsonschema<5,>=4.22; extra == "dev"
Requires-Dist: pytest<10,>=8; extra == "dev"
Requires-Dist: twine<7,>=5; extra == "dev"
Dynamic: license-file

# ecg-records

`ecg-records` measures 12-lead (or 1–8-channel) ECG signals and emits a small,
versioned JSON document, the **ECG Record**: fiducials, intervals,
amplitudes, areas, quality and provenance in raw-sample coordinates, with
explicit units, an explicit reason for every missing value, a stable address
for every value, and a per-field validation status. The Python import name is
`ecgfeat`.

> This software is research and engineering software. It is not a medical
> device and is not intended to diagnose, treat, cure, or prevent disease.
> Outputs require independent validation for the intended use and must not be
> used as a substitute for professional medical judgment.

The measurement pipeline (signal quality, multilead QRS detection, beat
grouping, representative beats, delineation) is inspired by publicly
documented 12-lead measurement practice. It is not a reproduction of any
proprietary product.

## Install

```bash
pip install ecg-records                  # measurements and ECG Records (NumPy, SciPy)
pip install "ecg-records[performance]"   # optional Numba acceleration
pip install "ecg-records[wfdb]"          # WFDB readers
pip install "ecg-records[viz]"           # plotting with ecgfeat.viz (adds Matplotlib)
pip install "ecg-records[interpret]"     # rule-based interpretation (ecginterpret)
```

Python 3.10–3.13. The core package depends only on NumPy and SciPy.

## Measure

```python
import numpy as np
from ecgfeat import ecg_record, dumps_record

leads = ["I", "II", "III", "aVR", "aVL", "aVF", "V1", "V2", "V3", "V4", "V5", "V6"]
signal = np.load("ecg.npy")        # shape (12, n_samples), channel-major, millivolts
record = ecg_record(signal, sampling_rate=500, lead_names=leads)   # profile="summary"
with open("ecg.record.json", "wb") as handle:
    handle.write(dumps_record(record))
```

Rows must be named explicitly; for fewer than 12 channels pass
`input_mode="limited"` (axis and formal QT are then `not_applicable`, raw
measurements stay available). Profiles: `summary` (default; under 24,000 bytes
for a 10 s, 12-lead, 10-beat record), `all` (every published measurement) and
`debug`. Dense matrices can move to a verified NPZ sidecar with
`serialize_record(record, sidecar_uri="ecg.dense.npz")`.

## Read and query

Reading records needs no NumPy, SciPy or plotting code:

```python
from ecgfeat import load_record, query_measurement, resolve_address

record = load_record("ecg.record.json")              # strict validation by default
qrs = query_measurement(record, "qrs_duration_ms", lead="V1", beat=3)
qrs.value, qrs.unit, qrs.absence, qrs.validation.tier, str(qrs.address)
# absence: None (measured), NullAbsence, UnmeasurableAbsence(reason) or NotApplicableAbsence(reason)

address = f"ecg-record:{record.record_id}@{record.schema_version}#/measurements/global/heart_rate_bpm/values"
resolve_address(record, address).value
```

Addresses follow `ecg-record:<record_id>@<schema_version>#<RFC 6901 pointer>`.
The JSON Schema and the validation-evidence registry ship in the package
(`ecgfeat/schemas/ecg-record/1.0/`).

## Plot

Plotting ships in this package as `ecgfeat.viz`; only Matplotlib is optional
(`pip install "ecg-records[viz]"`). `import ecgfeat` never imports Matplotlib,
and `pyplot` is never used.

```python
from ecgfeat.viz import plot_beat, plot_record

fig, axes = plot_record(signal, record, leads=["II", "V1", "V5"],
                        start_s=1.0, end_s=4.0, annotations="all")
fig.savefig("record.png", dpi=150)
fig, ax = plot_beat(signal, record, beat=3, lead="II")
```

`plot_beat_all_leads`, `plot_representative_beat` and `plot_quality_summary`
work the same way. Every function takes `(signal, record)` and returns
`(figure, axes)`. `signal` must be the exact array that produced the record:
its SHA-256 is checked against `/artifacts/raw_signal/sha256`, and a mismatch
raises `ecgfeat.viz.VisualizationInputError` (an `ECGInputError`). Pass
`figure=` to draw into an existing `Figure` or `SubFigure`. Every added artist
carries a `gid` starting with `ecgfeat.viz:`.

## Command line

```bash
ecg-record measure signal.npy --sampling-rate 500 --lead-names I II III aVR aVL aVF V1 V2 V3 V4 V5 V6 -o rec.json
ecg-record validate rec.json
ecg-record query rec.json qrs_duration_ms --lead V1 --beat 3
ecg-record batch manifest.jsonl --output-dir out --jobs 4
```

## Validation status

Every published field carries a validation status taken from the shipped
validation-evidence registry. In schema 1.0.0 **every field is
`unvalidated`**: benchmark history exists for several endpoints, but no field
has an approved evidence manifest yet, and a status can only be raised by
citing one. The four-class ST morphology is deliberately not published (it was
never validated and is anti-correlated with ischemia).

## Versions and compatibility

- The package version and the ECG Record schema version are independent. This
  release writes schema `1.0.0` and reads schema major `1`, tolerating
  additive fields from later minors.
- Legacy APIs (`ECGFeatureExtractor`, `to_dict`, `interpret`, `plot_*`,
  `ecgfeat.visualize`, the legacy result dataclasses) remain for a
  compatibility window. Legacy
  functions emit `ECGDeprecationWarning` on use; `ecgfeat.compat` provides the
  exact legacy contract without warnings. Removal is no earlier than 0.3.0.
