library(EGM)
#> 
#> Attaching package: 'EGM'
#> The following object is masked from 'package:stats':
#> 
#>     windowThe 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.
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:
# 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      0The WFDB standard defines 41 annotation types for surface electrocardiograms. These annotations can be broadly grouped into several categories:
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:
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_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) | 
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 | 
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 algorithmsThe 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)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)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.
ecgpuwaveOne of the common annotators used, called ecgpuwave,
demonstrates how the annotation system is leveraged.
The standard labels are used:
When using waveform boundary annotations like ( and
), the number column specifies which
waveform:
For T-wave annotations (t), the number
column describes morphology: