Skip to main content

An open-source framework for reproducible P-wave phenotyping

Project description

AtriaKit

An Open-Source Framework for Reproducible P-Wave Phenotyping

Tests

Quick Example

The fastest way to try AtriaKit hands-on is examples/demo.ipynb, which generates synthetic ECG data and runs it through the full pipeline end to end.

from atriakit import AnnotationsLoader, Pipeline

annotations = AnnotationsLoader().load("annotations.csv")
pipeline = Pipeline(ecg_base_path="path/to/dicom/root")

features = pipeline.run(annotations)
print(features.get_df().head())

Highlights

  • Temporal, morphological, nonlinear, and spatial (VCG) P-wave descriptors, each with an explicit mathematical definition; see the manuscript
  • Paired with ecg_annotator, an interactive tool for expert P-wave boundary annotation
  • Configuration-driven: filtering, boundary mode, and baseline correction are explicit and reproducible, not hard-coded; tune them via config classes directly in Python or a single YAML file that maps to them
  • Batch feature computation across recordings through a standardized Pipeline interface
  • Unit-tested reusable components

Atrial fibrillation (AF) is a major cause of cardiovascular morbidity, and the P-wave of the surface electrocardiogram is an important non-invasive marker of atrial remodeling and conduction heterogeneity. In practice, however, P-wave analysis is often implemented through custom or ad hoc signal-processing pipelines, which makes results harder to reproduce across studies. General ECG processing libraries exist, but they often do not provide the more specialized atrial and P-wave metrics needed for high-resolution AF research.

AtriaKit addresses that gap with a modular feature-extraction library (see Highlights above), built to scale from exploratory analysis to larger clinical datasets.

Implemented Feature Families

Overview of AtriaKit's P-wave feature families

The library currently includes:

  • Duration and Dispersion
  • Amplitude-Based P-Wave Features
  • Area and Area-To-Duration Ratio
  • P-Wave Terminal Force
  • Morphology and Inflection-Point Features
  • Fragmentation-Based Features
  • Complexity
  • Shannon Entropy and Sample Entropy
  • Atrial Rate and Heart Rate
  • Frontal and VCG Axis
  • VCG Area and Eigenfeatures
  • Signal-Averaged Vector-Magnitude P-Wave Amplitudes

The set is modular and can be extended with new metrics. For implementation details and mathematical definitions of each feature, see the AtriaKit manuscript (Citation).

Installation

pip install atriakit

To work from a clone of this repository instead (e.g. for development), install in editable mode:

pip install -e .

For development dependencies (testing, etc.):

pip install -e .[dev]

The package requires Python 3.12+.

Core API

The public package interface is exposed through atriakit:

from atriakit import (
    Annotations,
    AnnotationsLoader,
    ECGData,
    ECGDataset,
    ECGLoader,
    FeatureCalculators,
    FeatureComputationConfig,
    Pipeline,
    PipelineConfig,
    SegmentConfig,
    SignalPreprocessor,
    SignalPreprocessorConfig,
)

Important components:

  • ECGLoader: loads ECG waveforms from DICOM/IMA files and returns ECGData; register additional file types with ECGLoader().register(extension, loader)
  • ECGData: holds the raw signal array plus lead layout, and returns preprocessed lead signals via a SignalPreprocessor
  • AnnotationsLoader: loads a CSV or directory of annotation files into an Annotations object; also extensible via .register(extension, loader) for other annotation file formats
  • Annotations: wrapper around the annotation table
  • FeatureCalculators: computes ECG and VCG features for annotated segments, constructed with a SegmentConfig
    • SegmentConfig: baseline correction mode and leading-sample skip applied to extracted segments
  • Pipeline: runs batch feature extraction over a set of files, constructed with a PipelineConfig
  • PipelineConfig: bundles everything needed to tune a Pipeline run: segment-boundary and baseline-correction settings, preprocessing filters for both feature and morphology signals, feature-computation parameters (via FeatureComputationConfig), and beat-grouping tolerance
    • FeatureComputationConfig: per-call parameters for FeatureCalculators.compute_all (entropy, complexity, noise, morphology, and fragmentation settings)
  • SignalPreprocessor: applies notch filtering, bandpass filtering, baseline correction, and normalization as a reusable preprocessing object; each step is optional and toggled independently via SignalPreprocessorConfig
  • ECGDataset: computes per-lead mean/std across a set of files, for SignalPreprocessorConfig's z-score normalization

Usage

Pipeline is the main entry point: it batches feature computation across many recordings at once, matching each file to its rows in a combined annotations table (e.g. one annotations.csv covering a whole directory of DICOM/IMA files). Every config object ships with reasonable defaults, as in the Quick Example above: Pipeline(ecg_base_path=...) works with no further configuration, but you can tune it to your needs via a YAML file or by building the config objects directly in Python:

1. Configure via YAML (recommended)

Rather than building PipelineConfig/SignalPreprocessorConfig objects by hand, point Pipeline.from_yaml at a config file. See examples/pipeline_config.yaml for the full reference, covering paths, annotation boundary mode, preprocessing filters, and pipeline parameters (abbreviated below):

ecg_base_path: ./data
annotations_dir: ./data
pipeline:
  group_tolerance_ms: 200
  signal_preprocessor_config:
    lowcut: 1
    highcut: 40
    notch_freq: 50.0
  feature_computation:
    shannon_entropy_n_bins: 128
pipeline, annotations = Pipeline.from_yaml("pipeline_config.yaml")
result = pipeline.run(annotations)

Required annotation columns: file_path, lead, onset, offset, p_wave_id. Optional columns such as type, patient_id, and ignore are used when available.

2. Or configure directly in Python

For programmatic control (e.g. sweeping parameters in a script), pass a PipelineConfig straight to Pipeline:

from atriakit import FeatureComputationConfig, Pipeline, PipelineConfig, SignalPreprocessorConfig

pipeline = Pipeline(
    ecg_base_path="path/to/dicom/root",
    pipeline_config=PipelineConfig(
        signal_preprocessor_config=SignalPreprocessorConfig(
            lowcut=1.0, highcut=40.0, notch_freq=50.0
        ),
        morphology_preprocessor_config=SignalPreprocessorConfig(
            lowcut=1.0, highcut=30.0, notch_freq=50.0
        ),
        feature_computation=FeatureComputationConfig(shannon_entropy_n_bins=128),
    ),
)

3. Compute features for one recording directly

Unlike Pipeline, FeatureCalculators works on a single already-loaded recording, so its annotations must be pre-filtered to that one file, since onset/offset are sample indices into that specific signal:

from atriakit import AnnotationsLoader, ECGLoader, FeatureCalculators

ecg_data = ECGLoader().load("path/to/file.IMA")
annotations = AnnotationsLoader().load("annotations.csv")
file_annotations = annotations[annotations["file_path"] == "path/to/file.IMA"]

fc = FeatureCalculators()

area = fc.area(file_annotations, ecg_data)
max_amplitude = fc.max_amplitude(file_annotations, ecg_data)
all_features = fc.compute_all(file_annotations, ecg_data)

Preprocessing

Signal preprocessing is intentionally separated from feature extraction.

  • filter settings live in SignalPreprocessorConfig
  • runtime normalization state (mean / std) lives on SignalPreprocessor
  • ECGData delegates preprocessing to a SignalPreprocessor
  • FeatureCalculators can use separate preprocessors for standard signal features and morphology-specific features

Example:

from atriakit import ECGLoader, FeatureCalculators, SignalPreprocessor, SignalPreprocessorConfig

preprocessor = SignalPreprocessor(
    SignalPreprocessorConfig(lowcut=1.0, highcut=40.0, notch_freq=50.0)
)

ecg_data = ECGLoader().load("path/to/file.IMA")
lead_ii = ecg_data.get_lead_signal("II", preprocessor=preprocessor)

# FeatureCalculators takes the same kind of preprocessor, separately for
# standard signal features and morphology-specific features (both optional;
# see Core API above for the defaults used when omitted)
fc = FeatureCalculators(
    signal_preprocessor=preprocessor,
    morphology_preprocessor=SignalPreprocessor(
        SignalPreprocessorConfig(lowcut=1.0, highcut=30.0, notch_freq=50.0)
    ),
)

Repository Layout

AtriaKit/
├── atriakit/
│   ├── __init__.py
│   ├── datasets.py
│   ├── feature_calculator.py
│   ├── utils.py
│   ├── configs/
│   ├── features/
│   ├── io/
│   ├── models/
│   ├── preprocessing/
│   └── processing/
├── examples/
├── tests/
├── ecg_annotator/        # companion desktop annotation tool (separate package)
└── pyproject.toml

Main directories:

  • atriakit/: reusable ECG feature extraction package
  • atriakit/io/: DICOM/ECG loading, annotation-file loading, and waveform access
  • atriakit/models/: ECGData, Annotations, and the annotation column schema
  • atriakit/preprocessing/: signal and annotation preprocessing
  • atriakit/processing/: dataset utilities and the batch pipeline
  • atriakit/features/: individual feature implementations
  • atriakit/configs/: processing and feature configuration
  • examples/: demo material
  • tests/: unit tests
  • ecg_annotator/: standalone PyQt6 desktop app for manually annotating P-waves; a separate, independently packaged project, see its own README

Testing

Run the test suite with:

pytest

Or run a specific test module:

pytest tests/test_features.py -q

Notes

The repository favors a pragmatic research-code style, but the core package is structured to support gradual cleanup, extension, and more standardized use over time.

Citation

If you use AtriaKit in your research, please cite:

@software{atriakit,
  author  = {Kormushev, Nikolay},
  title   = {AtriaKit: An Open-Source Framework for Reproducible P-Wave Phenotyping},
  year    = {2026},
  url     = {https://github.com/nickormushev/AtriaKit}
}

License

MIT, see LICENSE.

Development Ideas

Areas that would likely improve maintainability further:

  • split feature_calculator.py into smaller focused modules over time
  • expand examples and API documentation
  • add parallelisation

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

atriakit-0.1.0.tar.gz (72.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

atriakit-0.1.0-py3-none-any.whl (58.7 kB view details)

Uploaded Python 3

File details

Details for the file atriakit-0.1.0.tar.gz.

File metadata

  • Download URL: atriakit-0.1.0.tar.gz
  • Upload date:
  • Size: 72.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for atriakit-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b5eb95aafba53fad6168ffcd7b8d9190c15219c37637244c372aaf39ee56a79e
MD5 00897bc17207ab5692877ead016c1b5f
BLAKE2b-256 951fad36f0ddf40b1a3109f76eb69a2d08429eab344eceda86d96c878745bae5

See more details on using hashes here.

File details

Details for the file atriakit-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: atriakit-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 58.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for atriakit-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ddabe9be55ed754741bc818a6a815280d88f7bb90eeef583bff229968f0e11d7
MD5 f04db4b985bf3ab110e3442092c377fd
BLAKE2b-256 2a94677c2c2970ba0dde09554e80a91ae9ec718eab535a165ad8bacec2e6026f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page