What’s new¶
2.0.1¶
Parsing¶
New format (experimental): XLE ECG (
.xle). 8-channel ECG recordings read from their reverse-engineered layout. The file does not state the voltage scale, so samples stay in raw ADC counts. ECGDataKit now reads 13 formats (see Supported Formats).XLE files can be anonymized: given name emptied, family name and patient ID replaced by the patient pseudonym, names and IDs replaced in the history and comment fields. Birth date and sex are kept.
2.0.0¶
Anonymization¶
New
ecgdatakit.anonymizepackage andecgdatakit anonymizecommand. ECG files are copied into anANONYMIZEDfolder with the patient’s name, the ECG ID and, when it can be trusted, the patient ID replaced by pseudonyms, and gets a new file name made of the pseudonyms. Raw files are only read. A CSV catalog links every raw file to its anonymized copy. See Anonymization.Every format ecgdatakit reads is supported, except EDAN Holter. Only the bytes of the identity values change: each file keeps its format, and each copy is read back and must give the same samples and fields before it is kept.
A single file, a folder, or several datasets (
--datasets) can be anonymized. Runs only process new, changed and deleted files.Patients are grouped only by patient folder (
--group-by-patient-folders,--patients-dir-name), never by an ID read in the files. Patient folders can be renamed to their pseudonyms (--anonymize-patient-folders).Identical files are the same ECG: they share one ECG pseudonym, and the catalog lists the copies of each file (
duplicatecolumn).ecgdatakit anonymize daemonkeeps a folder anonymized as files arrive,ecgdatakit anonymize shellshows what it is doing, and a Dockerfile runs it in a container.After each run, the raw files and the anonymized files are counted again from disk and checked (folders, patient folders, ECG files, patient IDs, duplicates, ECG IDs). The counts are printed, written to
anonymization_stats.csv, and shown byecgdatakit anonymize stats.Install with
pip install "ecgdatakit[anonymize]"(also part of[all]).
Documentation¶
New layout: header bar with search, grouped sidebar, “On this page” panel, and edit and report links on every page.
“API Reference” is renamed “Docs”. The function reference becomes “API Reference”, with Parsing, Processing, Plotting and Anonymization pages.
New Anonymization and Usage pages.
1.1.1¶
New format: AliveCor Kardia JSON¶
ECG recordings exported from the Kardia API (KardiaMobile and KardiaMobile 6L) can now be read. The library reads 12 formats (see Supported Formats).
The unfiltered signal goes to
record.leads. The signal filtered by AliveCor goes to the newrecord.leads_enhancedfield, which other formats leave empty.Samples are scaled with
amplitudeResolution(nanovolts per count), as described in the Kardia API documentation.The AliveCor algorithm result (for example
afib) is a machine interpretation.Kardia 12L recordings use another layout and raise
UnsupportedFormatError.
Detected format and parser¶
record.file_format.name holds the name of the detected format and
record.file_format.parser the parser that read the file. They are filled
in when the file is read through FileParser or parse_batch.
Annotations¶
These changes rename or remove annotation keys. Code that reads them may need updating.
A value with a field in
record.measurementsis stored only there, not also inrecord.annotations(Sierra and Mortara repeated some values).Each wave boundary has its own key. HL7 aECG and SCP-ECG no longer write them into one
wave_boundaries_mstext.Boundaries of the representative beat start with
median_, for examplemedian_p_onset_msormedian_q_onset(HL7 aECG, SCP-ECG, Mortara, GE MUSE, Sierra).Keys end with their unit when the format states it:
_ms,_samplesor_s.DICOM time-referenced annotations moved from
raw_metadata["waveform_annotations"]torecord.annotations, one key per wave type, for examplep_onset_samples.
1.1.0¶
This release makes the library stricter and more honest about what it reads. Some code that worked with 1.0 may now raise an error or give a different result. This page lists every change you may notice.
Reading files¶
Two formats removed. GE MAC 2000 and Mindray BeneHeart R12 are no longer supported. These files now raise
UnsupportedFormatError. The library reads 11 formats (see Supported Formats).EDAN Holter support is experimental. EDAN does not document its format, so every EDAN file now gives a warning. Check the values against the recorder’s own export before using them.
Leads come in millivolts by default.
FileParser().parse(path)converts every lead whose file gives a voltage scale to mV (auto_scale=True). Choose another unit withunits="uV"orunits="V". Leads whose file gives no scale stay in raw counts, and you get a warning. Withauto_scale=Falseyou get the numbers exactly as stored in the file, plus the scale needed to convert them (resolution,resolution_unit,offset).Only what the file stores. The library no longer works out values the file does not contain: no intervals computed from wave boundaries, no heart rate from RR intervals, no QTc from a guessed formula, no end date from start plus duration, no extra leads (such as III or aVR) built from the others, and no pacemaker or severity guessed from the text. A field the file does not give stays empty. Where a format specification defines a default (for example a sampling rate), it is used with a warning and marked in
raw_metadata.Who wrote the interpretation.
record.interpretation.sourceis"machine"for the device’s automatic statements, and"confirmed"or"overread"when a physician reviewed them (with the physician’s name and date when stored). When both exist, the device statements are kept inrecord.annotations["machine_interpretation"].Clearer errors. A file no parser recognises raises
UnsupportedFormatError(it is also aValueError, so existingexcept ValueErrorcode still works). Empty files raise instead of returning an empty record. A broken file raisesCorruptedFileErrorwith the reason. A missing optional package (for example pydicom for DICOM) raisesImportErrorwith the install command.
Records and leads¶
lead.to_physical()raisesRawSamplesErrorwhen the file gives no unit for the samples: uncalibrated counts cannot be turned into volts.record.to_json()produces strict JSON: missing or non-finite numbers are written asnull, neverNaN. For long recordings, write directly to a file withrecord.to_json(fp=f)to avoid building a huge string.
Parsing many files¶
parse_batch(..., on_error="warn")skips files that fail and reports each one as aBatchParseWarning, andon_error="ignore"skips them silently. The default,"raise", stops at the first failure.parse_batch(..., executor="serial")parses in the current process, which is faster for long Holter recordings. The default uses worker processes. On macOS and Windows, call it underif __name__ == "__main__":.
Signal processing¶
Filters, resampling, peak detection, spectra, quality and cleaning raise
ValueErrorfor signals that contain NaN or infinite values and for 2-D arrays, instead of returning wrong results. Normalization still accepts 2-D arrays, one lead per row.clean_ecgrejects options that the chosen method does not use, and raises clear errors when a backend cannot handle the signal.Normalized signals (min-max, z-score) have no unit: their
unitsis empty, so they cannot be mistaken for voltages.Leads derived from others (III, aVR, aVL, aVF) stay in raw counts only when both inputs are raw on the same scale. Otherwise they come back in physical units (the unit of lead I). Raw inputs with different scales and no unit raise
ValueError.Filtering a lead that is still in raw counts now takes its
offsetinto account, so the result converts to the right voltage.R-peak detection (
detect_r_peaks, Pan-Tompkins by default) is more reliable: better thresholds while learning, search back for missed beats, either QRS polarity, and any sampling rate.DeepFADE is experimental. It warns when used, is not validated for clinical use, and refuses leads that are still in raw counts: convert them to volts first.
Plotting¶
Time axes are exact (
sample / sampling rate). Beat plots show time relative to the R-peak, so 0 ms is the R-peak.Leads of different lengths are no longer cut to the shortest one.
Each plot shows the amplitude unit, or “raw counts”.
The optional ECG paper grid uses 0.2 s and 0.5 mV squares.
plot_reportuses the standard 3 x 4 layout (2.5 s per column) with a 10 s rhythm strip.Very long leads, such as a 24 h Holter, are drawn with a reduced number of points that keeps every peak, and you get a warning. Slice the lead to see every sample.
Plots no longer change your global matplotlib style.