Migration guide¶
From 0.1 to 0.2 is at the end of this page. The
first sections cover the move from the unpublished ecgfeat-dxl-inspired
working tree and the legacy ECGFeatures object to ecg-records.
In one minute¶
Before (legacy object; warns, and needs ecginterpret):
from ecgfeat import ECGFeatureExtractor
features = ECGFeatureExtractor().extract(signal, 500)
After:
import numpy as np
from ecgfeat import ecg_record, query_measurement
signal = np.load("ecg.npy")
leads = ["I", "II", "III", "aVR", "aVL", "aVF", "V1", "V2", "V3", "V4", "V5", "V6"]
record = ecg_record(signal, sampling_rate=500, lead_names=leads)
qrs = query_measurement(record, "qrs_duration_ms", lead="V1", beat=0)
The new API requires explicit lead names (the legacy extractor defaulted to the
canonical order when lead_names was omitted) and returns a versioned,
validated record instead of a mutable object graph.
Imports¶
| Old | New | Old path supported until |
|---|---|---|
from ecgfeat import ECGFeatureExtractor / ecgfeat.api |
ecgfeat.ecg_record(...) for records; ecgfeat.compat.api_v0.ECGFeatureExtractor for the exact legacy object |
warns now; removal no earlier than 0.3.0 |
ecgfeat.to_dict, ecgfeat.export.to_dict / prepare_json_export |
ecgfeat.dumps_record(record) / record_to_dict; legacy payload: ecgfeat.compat.export_v0 |
warns now; ≥ 0.3.0 |
ecgfeat.models.* dataclasses |
ecgfeat.compat.models_v0.* (same classes) |
silent alias; ≥ 0.3.0 |
ecgfeat.interpret, ecgfeat.clinical_rules, ecgfeat.glasgow_rules, … |
the separate ecginterpret distribution (0.2.1 on PyPI; it installs ecg-records[engine] 0.3): ecginterpret.analyze(signal) or ecginterpret.interpret_record(record, signal=...) |
aliases warn; ≥ 0.3.0 |
ecgfeat.plot_beat, plot_rep_beat, … / ecgfeat.visualize |
ecgfeat.viz.plot_beat(signal, record, ...) (pip install "ecg-records[viz]") |
warn; ≥ 0.3.0 |
ecgfeat.load_wfdb_mat, parse_wfdb_header |
ecgfeat.io.read_wfdb, ecgfeat.io.read_wfdb_header |
warn; ≥ 0.3.0 |
ecgfeat.delineate, ecgfeat.quality, ecgfeat.features, … (private engine) |
no public replacement; use record fields | alias warns; ≥ 0.3.0 |
ecgfeat.compat is the explicit legacy contract: it does not warn, and the
whole namespace is removed together no earlier than 0.3.0.
Values¶
Every published record value maps exactly to a legacy leaf through the
reviewed crosswalk (sample indices converted
to native sampling rate, milliseconds and microvolts rounded half-to-even).
Values that violate a published invariant are published as unmeasurable
instead. The legacy payload itself is unchanged: ecgfeat.compat.export_v0
reproduces the pre-migration bytes on 1,063 golden records.
Records vs. legacy object¶
The legacy object carries many intermediate quantities that ECG Record 1.0
does not publish (representative-lead morphology, rhythm inputs, P-wave
assessments). Consumers that need them keep using ecgfeat.compat during the
compatibility window; new quantities become record fields only with a unit,
absence semantics, provenance, a validation entry and size accounting.
Interpretation is no longer part of this package¶
The legacy extractor and the legacy JSON export include interpretation
sections, and interpretation now lives in the separate ecginterpret
distribution. Without it, ECGFeatureExtractor().extract(...), to_dict(...)
and ecgfeat.interpret raise an ImportError that names the missing
distribution. The record API never needs interpretation.
Turning warnings into errors¶
To find every remaining legacy call, run your tests with deprecation warnings as errors:
python -W error::FutureWarning -m pytest
ECGDeprecationWarning is a FutureWarning, so this catches exactly the
legacy calls. See Errors and warnings.
From ecg-records 0.1 to 0.2¶
Nothing that 0.1 published changes value, unit or absence encoding on the same input; 0.2 writes schema 1.1.0 (additive) and reads 1.0.0 records unchanged. The engine's measurement corrections since 0.1.0 are included, so values can differ from 0.1 on the same signal.
| 0.1 | 0.2 |
|---|---|
ecg_record(np.load(...), sampling_rate=..., lead_names=[...twelve names...]) |
ecg_record(read_signal(path)), or lead_names="standard_12" |
ecgfeat.io.read_wfdb (MATLAB pairs only), or the wfdb package |
read_signal (WFDB .dat/.mat, EDF/BDF, CSV, NumPy) |
map AVR/avr to aVR yourself |
standard names are normalized |
a loop over query_measurement |
record.to_dataframe("global" \| "leads" \| "beats" \| "long"), record.to_rows(), record.to_csv() |
| median of per-beat cells for a record-level interval | record.get("qt_interval_ms") (the engine's global value) |
ecg-record measure x.npy --sampling-rate 500 --lead-names ... |
ecg-record measure x.hea (metadata from the file) |
ecg-record batch --jobs N with threads |
worker processes; directories and globs; --table |
plot_record with per-lead y-scales |
one shared millivolt span by default (y_scale="independent" for the old look) |
| five fiducial hues | three hues by wave plus marker shape by landmark |
ExtractionConfig |
ECGConfig (ExtractionConfig warns; removed no earlier than 0.4.0) |
ecg_record(...) then ecginterpret.interpret_record(record, signal=...) |
ecginterpret.analyze(signal): one extraction for both |
Behaviour changes to note: summary records are up to 30,000 bytes (the
reference case is 29,084); plot_quality_summary shows a noise heat map for
records that carry quality metrics (metrics="rms" for the 0.1 bar chart);
ecg-record batch --jobs N uses processes (--threads for threads).