Source code for neurokit2.hrv.hrv

# -*- coding: utf-8 -*-
import matplotlib.gridspec as gs
import matplotlib.pyplot as plt
import pandas as pd

from ..stats import summary_plot
from .hrv_frequency import _hrv_frequency_show, hrv_frequency
from .hrv_nonlinear import _hrv_nonlinear_show, hrv_nonlinear
from .hrv_rsa import hrv_rsa
from .hrv_time import hrv_time
from .hrv_utils import _hrv_format_input
from .intervals_process import intervals_process


[docs] def hrv(peaks, sampling_rate=1000, show=False, **kwargs): """**Heart Rate Variability (HRV)** This function computes all HRV indices available in NeuroKit. It is essentially a convenience function that aggregates results from the :func:`time domain <hrv_time>`, :func:`frequency domain <hrv_frequency>`, and :func:`non-linear domain <hrv_nonlinear>`. .. tip:: We strongly recommend checking our open-access paper `Pham et al. (2021) <https://doi.org/10.3390/s21123998>`_ on HRV indices as well as `Frasch (2022) <https://www.ncbi.nlm.nih.gov/pmc/articles/PMC9307944/>`_ for more information. Parameters ---------- peaks : dict Samples at which R-peaks occur. Can be a list of indices or the output(s) of other functions such as :func:`.ecg_peaks`, :func:`.ppg_peaks`, :func:`.ecg_process` or :func:`bio_process`. Can also be a dict containing the keys `RRI` and `RRI_Time` to directly pass the R-R intervals and their timestamps, respectively. sampling_rate : int, optional Sampling rate (Hz) of the continuous cardiac signal in which the peaks occur. Should be at least twice as high as the highest frequency in vhf. By default 1000. show : bool, optional If ``True``, returns the plots that are generated for each of the domains. Returns ------- DataFrame Contains HRV indices in a DataFrame. If RSP data was provided (e.g., output of :func:`bio_process`), RSA indices will also be included. See Also -------- hrv_time, hrv_frequency, hrv_nonlinear, hrv_rsa, .ecg_peaks, .ppg_peaks Examples -------- **Example 1**: Only using a list of R-peaks locations .. ipython:: python import neurokit2 as nk import matplotlib.pyplot as plt plt.rc('font', size=8) # Download data data = nk.data("bio_resting_5min_100hz") # Clean signal and Find peaks ecg_cleaned = nk.ecg_clean(data["ECG"], sampling_rate=100) peaks, info = nk.ecg_peaks(ecg_cleaned, sampling_rate=100, correct_artifacts=True) # Compute HRV indices @savefig p_hrv1.png scale=100% hrv_indices = nk.hrv(peaks, sampling_rate=100, show=True) @suppress plt.close() **Example 2**: Compute HRV directly from processed data .. ipython:: python # Download data data = nk.data("bio_resting_5min_100hz") # Process signals, info = nk.bio_process(data, sampling_rate=100) # Get HRV nk.hrv(signals, sampling_rate=100) References ---------- * Pham, T., Lau, Z. J., Chen, S. H. A., & Makowski, D. (2021). Heart Rate Variability in Psychology: A Review of HRV Indices and an Analysis Tutorial. Sensors, 21(12), 3998. https://doi.org/10.3390/s21123998 * Frasch, M. G. (2022). Comprehensive HRV estimation pipeline in Python using Neurokit2: Application to sleep physiology. MethodsX, 9, 101782. * Stein, P. K. (2002). Assessing heart rate variability from real-world Holter reports. Cardiac electrophysiology review, 6(3), 239-244. * Shaffer, F., & Ginsberg, J. P. (2017). An overview of heart rate variability metrics and norms. Frontiers in public health, 5, 258. """ # Get indices out = [] # initialize empty container # Gather indices out.append(hrv_time(peaks, sampling_rate=sampling_rate)) out.append(hrv_frequency(peaks, sampling_rate=sampling_rate)) out.append(hrv_nonlinear(peaks, sampling_rate=sampling_rate)) # Compute RSA if rsp data is available if isinstance(peaks, pd.DataFrame): if ("RSP_Phase" in peaks.columns) and ("RSP_Phase_Completion" in peaks.columns): rsp_signals = peaks[["RSP_Phase", "RSP_Phase_Completion"]] rsa = hrv_rsa(peaks, rsp_signals, sampling_rate=sampling_rate) out.append(pd.DataFrame([rsa])) out = pd.concat(out, axis=1) # Plot if show: if isinstance(peaks, dict): peaks = peaks["ECG_R_Peaks"] # Indices for plotting out_plot = out.copy(deep=False) _hrv_plot(peaks, out_plot, sampling_rate, **kwargs) return out
# ============================================================================= # Plot # ============================================================================= def _hrv_plot(peaks, out, sampling_rate=1000, interpolation_rate=100, **kwargs): fig = plt.figure(constrained_layout=False) spec = gs.GridSpec(ncols=2, nrows=2, height_ratios=[1, 1], width_ratios=[1, 1]) # Arrange grids ax_distrib = fig.add_subplot(spec[0, :-1]) ax_distrib.set_xlabel("R-R intervals (ms)") ax_distrib.set_title("Distribution of R-R intervals") ax_psd = fig.add_subplot(spec[1, :-1]) spec_within = gs.GridSpecFromSubplotSpec(4, 4, subplot_spec=spec[:, -1], wspace=0.025, hspace=0.05) ax_poincare = fig.add_subplot(spec_within[1:4, 0:3]) ax_marg_x = fig.add_subplot(spec_within[0, 0:3]) ax_marg_x.set_title("Poincaré Plot") ax_marg_y = fig.add_subplot(spec_within[1:4, 3]) plt.tight_layout(h_pad=0.5, w_pad=0.5) # Distribution of RR intervals rri, rri_time, rri_missing = _hrv_format_input(peaks, sampling_rate=sampling_rate) ax_distrib = summary_plot(rri, ax=ax_distrib, **kwargs) # Poincare plot out.columns = [col.replace("HRV_", "") for col in out.columns] _hrv_nonlinear_show(rri, rri_time=rri_time, rri_missing=rri_missing, out=out, ax=ax_poincare, ax_marg_x=ax_marg_x, ax_marg_y=ax_marg_y) # PSD plot rri, rri_time, sampling_rate = intervals_process( rri, intervals_time=rri_time, interpolate=True, interpolation_rate=interpolation_rate, **kwargs ) frequency_bands = out[["ULF", "VLF", "LF", "HF", "VHF"]] _hrv_frequency_show(rri, frequency_bands, sampling_rate=sampling_rate, ax=ax_psd)