CardiacDP

CardiacDP (Cardiac Data Processing) can automatically read and collate heart rate data, and compute average heart rate per analysis interval (sequence). The analysis employs the autocorrelation function (ACF) with a genetic algorithm framework to identify periods of repeating waveforms within each sequence. These candidate heart rates of sub-sequences are then evaluated either by the autocorrelation value or a tracking index (TI), and finally weighted as the final output.

Package structure

Installation

install.packages("CardiacDP")

# Or from GitHub
devtools::install_github("Vicellken/CardiacDP")

# Or the source package from GitHub:
# Vector of package names
packages <- c("data.table", "doParallel", "dplyr", "foreach", "ggplot2", "purrr", "RColorBrewer", "stringr")

lapply(packages, function(pkg) {
  if (!require(pkg, character.only = TRUE)) {
    install.packages(pkg)
  }
})

# Install the source package
install.packages("CardiacDP_0.4.2.tar.gz", repos = NULL, type = "source")

Example

This is an example showing the complete analysis pipeline:

library(CardiacDP)

zip_path <- "~/rawfiles.zip" # PATH_TO_ZIP_FILE

# csv_path <- "" # PATH_TO_COLLATED_CSV

# run computeHR() for average heart rate analysis (no files are written by default)
output <- computeHR(
  file_path = csv_path, # collatedata() will automatically run if zip_path is directly provided here
  save_outputs = TRUE,
  output_dir = NULL, # PATH_TO_STORE_OUTPUTS
  verbose = TRUE)

The user can access the output by the channel name. finalsubseq is a list showing the positions and durations of the final periodic sub-sequences determined for each sequence. They are presented as data tables (s = start index of the sub-sequence; e = end index of the sub-sequence; p = which of the initial population the sub-sequence is derived from; and f = duration of the sub-sequence), the rows of which represent separate final sub-sequences.

# positions (in indices) and durations of the final sub-sequences
# NOTE: the results are not included here for simplicity. For more details please refer to Supplementary Information S4 of the publication / User guideline.pdf

# output[["finalsubseq"]][["Channel A"]]

The corresponding candidate heart rates per sub-sequences can be found in candidateHR (ACF = autocorrelation value; lag = time lag; and hr = heart rate).

# candidate heart rates of the final sub-sequences
# NOTE: the results are not included here for simplicity. For more details please refer to Supplementary Information S4 of the publication / User guideline.pdf

# output[["candidateHR"]][["Channel A"]]

The final results after evaluating the candidate heart rates, checking for resolution and weighting for durations can eventually be obtained from results_ACF and results_TI. These results referred to evaluating the candidate heart rates by merely autocorrelation values (i.e. the “ACF + GA” approach in the publication) or the tracking index (i.e. the “ACF + GA +TI” approach in the publication) respectively. Each of them consists of 1) the details of the sub-sequences (subseqHR); 2) the weighted heart rate per sequence (weightedHR); and 3) a plot of weighted heart rate against time (plot).

## results obtained from evaluating the candidate heart rates by autocorrelation values
# output[["results_ACF"]][["Channel A"]]

# results obtained from evaluating the candidate heart rates by the tracking index
# output[["results_TI"]][["Channel A"]]

Interpret results

Variable Content
finalsubseq A list of positions and durations of the final periodic sub-sequences
candidateHR A list of candidate heart rates extracted from ACF for each sub-sequence
results_ACF Results obtained from evaluating the candidate heart rates of each sub-sequence based on autocorrelation values (i.e. following the “ACF + GA” approach as described in the main manuscript). Consisted of three items: 1) subseqHR: a list of sub-sequences and the corresponding heart rates and durations; 2) weightedHR: a list of final heart rates per sequence after weighing; and 3) plot: a plot of final heart rates against time
results_TI Results obtained from evaluating the candidate heart rates of each sub-sequence using a tracking index (i.e. following the “ACF + GA + TI” approach as described in the main manuscript). Consisted of three items: 1) subseqHR: a list of sub-sequences and the corresponding heart rates and durations; 2) weightedHR: a list of final heart rates per sequence after weighing; and 3) plot: a plot of final heart rates against time

Automatically saved files

By default, computeHR() does not write any files. If you want CSV/PNG outputs, set save_outputs = TRUE and optionally provide output_dir (if output_dir is NULL, it defaults to tempdir()):

csv_path <- system.file("extdata", "example.csv", package = "CardiacDP")
output <- computeHR(
  file_path = csv_path,
  save_outputs = TRUE,
  output_dir = tempdir()
)

CSV Files

For each channel and method (ACF and TI), the following CSV files are saved:

Note: Channel names with spaces (e.g., “Channel A”) are converted to underscores (e.g., “Channel_A”) in filenames.

PNG Files

For each channel and method, heart rate plots are saved:

Column descriptions

weightedHR CSV files contain:

subseqHR CSV files contain:

Reproducing plots from saved CSV files

The saved CSV files contain all the data needed to reproduce the heart rate plots. Use the weightedHR CSV files for plotting:

library(ggplot2)
library(RColorBrewer)
library(data.table)

# Read the saved weighted heart rate data (example; assumes you ran computeHR(save_outputs=TRUE))
channel <- "Channel A"
data <- fread(paste0(gsub(" ","_",channel),"_TI_weightedHR.csv"))

# Create the plot (matching the package output)
palette <- brewer.pal(n = 11, name = "RdYlBu")
names(palette) <- seq(0, 10, 1) / 10

# analysis interval (by default 1 min)
an_in <- 1

ggplot() +
  geom_point(
    data = data,
    aes(x = ix * an_in, y = whr, fill = factor(floor(wACF * 10) / 10)),
    colour = "black", shape = 21, size = 4, alpha = 0.8
  ) +
  scale_fill_manual(
    name = "ACF", values = palette, na.value = NA,
    na.translate = FALSE, guide = "legend"
  ) +
  scale_y_continuous(
    name = "Heart rate (bpm)",
    breaks = seq(0, ceiling(max(data$whr, na.rm = TRUE) / 50) * 50, 50),
    limits = c(0, ceiling(max(data$whr, na.rm = TRUE) / 50) * 50),
    expand = c(0, 0)
  ) +
  scale_x_continuous(
    name = "Time (min)",
    breaks = seq(0, ceiling(max(data$Time_min, na.rm = TRUE) / 30) * 30, 30),
    limits = c(0, ceiling(max(data$Time_min, na.rm = TRUE) / 30) * 30),
    expand = c(0, 0)
  ) +
  theme_linedraw() +
  theme(
    text = element_text(size = 12, colour = "black"),
    panel.grid.minor = element_blank(),
    panel.border = element_rect(fill = NA, colour = "black", linewidth = 1)
  )

Key columns for plotting:

mirror server hosted at Truenetwork, Russian Federation.