Metadata-Version: 2.4
Name: ecg-records
Version: 0.3.1
Summary: 12-lead ECG measurement into versioned, queryable ECG Records, with file readers and clinical-format plots (research and engineering software; not a medical device)
Author: humansys-lab
Maintainer: humansys-lab
License-Expression: Apache-2.0
Project-URL: Homepage, https://humansys-lab.github.io/ecg-records/
Project-URL: Documentation, https://humansys-lab.github.io/ecg-records/
Project-URL: Repository, https://github.com/humansys-lab/ecg-records
Project-URL: Issues, https://github.com/humansys-lab/ecg-records/issues
Project-URL: Changelog, https://humansys-lab.github.io/ecg-records/changelog/
Keywords: ecg,electrocardiography,signal-processing,delineation,physionet,wfdb,edf,visualization,qt-interval
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: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Classifier: Topic :: Scientific/Engineering :: Visualization
Classifier: Typing :: Typed
Requires-Python: <3.15,>=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: engine
Requires-Dist: ecg-records-engine<0.4,>=0.3.0; extra == "engine"
Provides-Extra: viz
Requires-Dist: matplotlib<4,>=3.7; extra == "viz"
Provides-Extra: interactive
Requires-Dist: plotly<7,>=5.20; extra == "interactive"
Provides-Extra: table
Requires-Dist: pandas<4,>=2.0; extra == "table"
Requires-Dist: pyarrow>=14; extra == "table"
Provides-Extra: interpret
Requires-Dist: ecginterpret<0.3,>=0.2; extra == "interpret"
Provides-Extra: performance
Requires-Dist: numba<0.69,>=0.59; extra == "performance"
Provides-Extra: wfdb
Requires-Dist: wfdb<5,>=4.1; extra == "wfdb"
Provides-Extra: all
Requires-Dist: ecg-records-engine<0.4,>=0.3.0; extra == "all"
Requires-Dist: matplotlib<4,>=3.7; extra == "all"
Requires-Dist: plotly<7,>=5.20; extra == "all"
Requires-Dist: pandas<4,>=2.0; extra == "all"
Requires-Dist: pyarrow>=14; extra == "all"
Requires-Dist: ecginterpret<0.3,>=0.2; extra == "all"
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) ECGs and emits a small,
versioned JSON document, the **ECG Record**: record-level intervals, axes and
rhythm measures, median-beat values per lead, and per-beat, per-lead
fiducials, intervals and amplitudes -- each with an explicit unit, an explicit
reason for every missing value, a feature state, a stable address and a
validation status. It reads WFDB, EDF/BDF, CSV and NumPy files, draws
clinical-format plots, and pairs with the optional rule-based
[`ecginterpret`](https://pypi.org/project/ecginterpret/). The 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.

## Install

```bash
pip install "ecg-records[engine]"        # records + the compiled measurement engine
pip install ecg-records                  # records only (read, query, plot); no measuring
pip install "ecg-records[viz]"           # + Matplotlib plots (ecgfeat.viz)
pip install "ecg-records[table]"         # + pandas DataFrames and Parquet tables
pip install "ecg-records[interpret]"     # + rule-based interpretation (ecginterpret)
pip install "ecg-records[all]"           # everything above + Plotly
```

Python 3.10–3.14. Optional: `wfdb` (exotic WFDB layouts), `interactive` (Plotly).

The engine (`ecg-records-engine`, compiled wheels for Linux, macOS and Windows)
is free for noncommercial use under the PolyForm Noncommercial License 1.0.0
and needs a commercial licence key otherwise; `ecg-records` itself is
Apache-2.0. Keys are verified offline and never restrict functionality. See
the documentation page *Licensing* and `ecgfeat.license_info()`.

## Ten lines

```python
import ecgfeat
from ecgfeat import viz

signal = ecgfeat.load_example("sinus")        # bundled PTB-XL record; or ecgfeat.read_signal("x.hea")
record = ecgfeat.ecg_record(signal)            # validated ECG Record, schema 1.1.0
print(record.summary())                        # rate, P/PR/QRS/QT, QTc, axes
record.get("qt_interval_ms")                   # record level, ms
record.get("median_st_60ms_uv", lead="V2")     # median beat of one lead, µV
record.get("qrs_duration_ms", lead="V1", beat=3)
record.to_dataframe("leads")                   # pandas: one row per lead
figure, ax = viz.plot_ecg(signal, record)      # 12-lead ECG paper at 25 mm/s, 10 mm/mV
```

## Read files

```python
signal = ecgfeat.read_signal("ptbxl/records500/00000/00001_hr.hea")  # WFDB 16/212/24/32/61/80, .mat
signal = ecgfeat.read_signal("study.edf", channels=["II", "V5"])     # EDF, EDF+, BDF
signal = ecgfeat.read_signal("export.csv")                           # header row + time column
record = ecgfeat.record_from_file("long.edf", start_s=60, end_s=70)  # read + window + measure
records = ecgfeat.ecg_record_segments(signal, segment_s=10)          # long recordings, window by window
```

Arrays work too: `ecg_record(array, sampling_rate=500, lead_names="standard_12")`.
Lead names are normalized (`AVR`, `ECG aVR` → `aVR`). Fewer than 12 channels
need `input_mode="limited"`; axes and formal QT are then `not_applicable`.

## Read records back

Reading needs no NumPy, SciPy or plotting code:

```python
from ecgfeat import dumps_record, load_record

open("rec.json", "wb").write(dumps_record(record))
record = load_record("rec.json")                       # strict validation
result = record.query("qt_interval_ms")                # value, unit, absence, feature_state, address, validation
result.feature_state                                   # e.g. {'status': 'observed', 'reason': 'value_available'}
record.to_csv("rec.csv")                               # one row per published cell
```

Values the engine kept but flagged (a QT that failed the reportability gate)
are published with a feature state other than `observed`; check it before use.
Addresses: `ecg-record:<record_id>@<schema_version>#<RFC 6901 pointer>`.

## Plot

`ecgfeat.viz` (the `viz` extra) never imports `pyplot`; every function takes
`(signal, record)` -- verified by SHA-256 -- and returns `(figure, axes)`:
`plot_ecg` (ECG paper, 3x4/6x2/12x1 with rhythm strips, real millimetres),
`plot_record`, `plot_beat`, `plot_beat_all_leads`, `plot_representative_beat`,
`plot_median_beats`, `plot_st_segments`, `plot_rhythm`, `plot_quality_summary`,
plus `plot_record_interactive` (Plotly) and `annotations_to_dict` for web
front-ends. Themes: `viz.use_style("dark")`, `viz.PlotStyle().replace(...)`.

## Command line

```bash
ecg-record measure ptbxl/00001_hr.hea -o rec.json       # rate and leads from the file
ecg-record summary rec.json
ecg-record table rec*.json -o global.csv                 # or .parquet; --kind long
ecg-record plot ptbxl/00001_hr.hea --kind paper -o ecg.png
ecg-record batch 'ptbxl/**/*.hea' --output-dir out --jobs 8 --table out/global.csv
ecg-record examples
```

## Validation status

Every field's status comes from the validation-evidence registry shipped with
its schema. In schema 1.1.0 the record-level **P duration, PR, QRS and QT** are
`benchmark_validated`: on LUDB 1.0.1 they meet the IEC 60601-2-25 global
interval limits against the expert annotations, evaluated the CSE way. On a
3,000-record PTB-XL hold-out, QRS and QT also agree with GE 12SL within those
limits; P duration and PR do not (two machine algorithms disagree on PR by
more than the limit too). Everything else is `unvalidated` -- per-lead
fiducials, for instance, do not meet the CSE delineation tolerances on LUDB.
Evidence manifests and tools live in the repository (`benchmarks/evidence/`).

## Versions and compatibility

- Package and schema versions are independent. 0.2.x writes schema `1.1.0` and
  reads schema major `1`; schema 1.1 is additive, and the 0.1.0 reader loads
  1.1 records.
- Legacy APIs (`ECGFeatureExtractor`, `to_dict`, `interpret`, `plot_*`, ...) warn
  and remain until 0.3.0; `ecgfeat.compat` provides the exact legacy contract.

The bundled example ECGs are PTB-XL 1.0.1 records (Wagner et al., PhysioNet
2020, CC BY 4.0); see `NOTICE`.

Documentation: <https://github.com/humansys-lab/ECG-feature-extraction-/tree/main/docs/site>
