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. 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
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
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
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:
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
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.0and reads schema major1; 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.compatprovides 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
Metadata
Release files for ecg-records 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| ecg_records-0.3.0.tar.gz | 439.7 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ecg_records-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 909.1 kB
Release files / ecg_records-0.3.0.tar.gz
| Download URL | ecg_records-0.3.0.tar.gz |
|---|---|
| Size | 439.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9dfa58edbf73d0fcd229e2dccb88ee5a18b43572403200b5751940715f57a217
|
|
BLAKE2b-256 checksum How to use checksums |
1a2e9382ab01b9e6c473c9da9f1be65eef5d1af3ecd2986f3bf512fc2112e4e4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / ecg_records-0.3.0-py3-none-any.whl
| Download URL | ecg_records-0.3.0-py3-none-any.whl |
|---|---|
| Size | 469.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8e150297b7dde84d2a6218c720c5b043c04eb69f992ada086ac73febd3fe8fff
|
|
BLAKE2b-256 checksum How to use checksums |
253d36751acfd830724fd21e6f17946407ee830736cff4dbb38e6b2d75a84315
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Security for ecg-records 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.