library(EGM)
#>
#> Attaching package: 'EGM'
#> The following object is masked from 'package:stats':
#>
#> windowElectrocardiogram Annotations
WFDB Annotation Standards
The WFDB (Waveform Database) software package provides a standardized system for annotating cardiac signals, predominately surface electrocardiogram (ECG) data. Annotations are polymorphic, meaning multiple annotation sets can be applied to a single signal dataset. The limitation is that these are constrained to physiological events associated with surface ECGs.
Annotation Table Structure
All WFDB-compatible annotations in the EGM package are
stored as annotation_table objects. The columns are
type-specific, which allows them to be easily stored. These tables
contain the following required columns:
- annotator: Name of the annotation function or creator (e.g., “sqrs”, “ecgpuwave”, “manual”)
- time: Time stamp constructed from sample number and sampling frequency (format: HH:MM:SS.mmm)
- sample: Integer index of the annotation position in the signal
- type: Single character symbol describing the annotation type (see annotation types below)
- subtype: Single character providing additional classification
- channel: Integer indicating which signal channel the annotation applies to
- number: Additional numeric qualifier providing context-specific information
# Create annotations for detected R-peaks
# Example
ann <- annotation_table(
annotator = "qrs",
sample = c(100, 350, 600, 850),
type = "N",
frequency = 250,
channel = 0
)
# Print
ann
#> <annotation_table: 4 `qrs` annotations>
#> time sample type subtype channel number
#> <char> <num> <char> <char> <num> <int>
#> 1: 00:00:00.4 100 N 0 0
#> 2: 00:00:01.4 350 N 0 0
#> 3: 00:00:02.4 600 N 0 0
#> 4: 00:00:03.4 850 N 0 0Standard ECG Annotation Types
The WFDB standard defines 41 annotation types for surface electrocardiograms. These annotations can be broadly grouped into several categories:
Beat Annotations
Beat annotations mark individual cardiac cycles and their characteristics:
# Load internal annotation data
beat_symbols <- c("N", "L", "R", "a", "V", "F", "J", "A", "S", "E", "j", "/", "Q", "~")
beat_labels <- EGM:::.surface_annotations[EGM:::.surface_annotations$symbol %in% beat_symbols, ]
knitr::kable(
beat_labels[, c("symbol", "mnemonic", "description")],
col.names = c("Symbol", "Mnemonic", "Description"),
row.names = FALSE,
caption = "Beat Annotation Types"
)| Symbol | Mnemonic | Description |
|---|---|---|
| N | NORMAL | Normal beat |
| L | LBBB | Left bundle branch block beat |
| R | RBBB | Right bundle branch block beat |
| a | ABERR | Aberrated atrial premature beat |
| V | PVC | Premature ventricular contraction |
| F | FUSION | Fusion of ventricular and normal beat |
| J | NPC | Nodal (junctional) premature beat |
| A | APC | Atrial premature contraction |
| S | SVPB | Premature or ectopic supraventricular beat |
| E | VESC | Ventricular escape beat |
| j | NESC | Nodal (junctional) escape beat |
| / | PACE | Paced beat |
| Q | UNKNOWN | Unclassifiable beat |
| ~ | NOISE | Signal quality change |
Key beat types:
- N (NORMAL): Normal sinus beat
- V (PVC): Premature ventricular contraction
- A (APC): Atrial premature contraction
- L/R (LBBB/RBBB): Bundle branch block beats
- F (FUSION): Fusion of ventricular and normal beat
- / (PACE): Paced beat
Waveform Boundary Annotations
These mark the beginning, peak, and end of ECG waveforms:
wave_symbols <- c("p", "t", "u", "(", ")")
wave_labels <- EGM:::.surface_annotations[EGM:::.surface_annotations$symbol %in% wave_symbols, ]
knitr::kable(
wave_labels[, c("symbol", "mnemonic", "description")],
col.names = c("Symbol", "Mnemonic", "Description"),
row.names = FALSE,
caption = "Waveform Boundary Annotations"
)| Symbol | Mnemonic | Description |
|---|---|---|
| p | PWAVE | P-wave peak |
| t | TWAVE | T-wave peak |
| u | UWAVE | U-wave peak |
| ( | WFON | Waveform onset |
| ) | WFOFF | Waveform end |
Rhythm and Signal Quality Annotations
rhythm_symbols <- c("+", "|", "s", "T", "~", "x")
rhythm_labels <- EGM:::.surface_annotations[EGM:::.surface_annotations$symbol %in% rhythm_symbols, ]
knitr::kable(
rhythm_labels[, c("symbol", "mnemonic", "description")],
col.names = c("Symbol", "Mnemonic", "Description"),
row.names = FALSE,
caption = "Rhythm and Signal Quality Annotations"
)| Symbol | Mnemonic | Description |
|---|---|---|
| ~ | NOISE | Signal quality change |
| | | ARFCT | Isolated QRS-like artifact |
| s | STCH | ST change |
| T | TCH | T-wave change |
| + | RHYTHM | Rhythm change |
| x | NAPC | Non-conducted P-wave (blocked APB) |
Specialized Annotations
special_symbols <- c("*", "D", "\"", "=", "!", "[", "]", "@", "r", "^", "B", "e", "n", "f")
special_labels <- EGM:::.surface_annotations[EGM:::.surface_annotations$symbol %in% special_symbols, ]
knitr::kable(
special_labels[, c("symbol", "mnemonic", "description")],
col.names = c("Symbol", "Mnemonic", "Description"),
row.names = FALSE,
caption = "Specialized Annotations"
)| Symbol | Mnemonic | Description |
|---|---|---|
| * | SYSTOLE | Systole |
| D | DIASTOLE | Diastole |
| ” | NOTE | Comment annotation |
| = | MEASURE | Measurement annotation |
| B | BBB | Left or right bundle branch block |
| ^ | PACESP | Non-conducted pacer spike |
| ! | FLWAV | Ventricular flutter wave |
| [ | VFON | Start of ventricular flutter/fibrillation |
| ] | VFOFF | End of ventricular flutter/fibrillation |
| e | AESC | Atrial escape beat |
| n | SVESC | Supraventricular escape beat |
| @ | LINK | Link to external data (aux_note contains URL) |
| f | PFUS | Fusion of paced and normal beat |
| r | RONT | R-on-T premature ventricular contraction |
Common Annotation File Types
When working with WFDB files, annotations are stored with specific file extensions that indicate the annotator used:
-
.atr: Manually reviewed and corrected reference annotations -
.ann: General annotation file -
.ecgpuwave: Surface ECG wave boundaries (P, QRS, T waves) generated by the ecgpuwave algorithm -
.sqrs,.wqrs,.gqrs: R-peak detections from different QRS detection algorithms
Accessing All Standard Annotations
The complete list of standard WFDB annotations can be accessed using:
# View all standard ECG annotation types
wfdb_annotation_labels()
# Filter for specific symbols
wfdb_annotation_labels(symbol = c("N", "V", "A"))
# Decode annotations in an existing annotation table
ann <- annotation_table(
annotator = "example",
sample = c(100, 200),
type = c("N", "V")
)
# Add human-readable descriptions
wfdb_annotation_decode(ann)Example: Working with ECG Annotations
Here’s a practical example of reading, interpreting, and visualizing ECG annotations:
# Read an ECG with annotations
record_path <- system.file('extdata', package = 'EGM')
ecg <- read_wfdb(
record = "muse-sinus",
record_dir = record_path
)
# Read associated annotations (if they exist)
ann <- read_annotation(
record = "muse-sinus",
annotator = "ecgpuwave",
record_dir = record_path
)
# Decode annotation types
ann_decoded <- wfdb_annotation_decode(ann)
head(ann_decoded)Intracardiac Electrogram Annotations
This is a work in progress, where we aim to define and implement a comprehensive set of annotations for intracardiac electrograms that are compatible with the standard WFDB annotation system.
Examples
ecgpuwave
One of the common annotators used, called ecgpuwave,
demonstrates how the annotation system is leveraged.
The standard labels are used:
- p (PWAVE): P-wave peak
- t (TWAVE): T-wave peak
- ( (WFON): Waveform onset
- ) (WFOFF): Waveform end
When using waveform boundary annotations like ( and
), the number column specifies which
waveform:
- 0 = P wave
- 1 = QRS complex
- 2 = T wave
For T-wave annotations (t), the number
column describes morphology:
- 0 = Normal
- 1 = Inverted
- 2 = Positive
- 3 = Negative
- 4 = Biphasic (negative-positive)
- 5 = Biphasic (positive-negative)