Extract and Visualize Individual Heartbeats
Extract and Visualize Individual Heartbeats#
This example can be referenced by citing the package.
This example shows how to use NeuroKit to extract and visualize the QRS complexes (individual heartbeats) from an electrocardiogram (ECG).
# Load NeuroKit and other useful packages import neurokit2 as nk import numpy as np import matplotlib.pyplot as plt
# This "decorative" cell should be hidden from the docs once this is implemented: # https://github.com/microsoft/vscode-jupyter/issues/1182 plt.rcParams['figure.figsize'] = [15, 5] # Bigger images plt.rcParams['font.size']= 14
Extract the cleaned ECG signal#
In this example, we will use a simulated ECG signal. However, you can use any of your signal (for instance, extracted from the dataframe using the read_acqknowledge().
# Simulate 30 seconds of ECG Signal (recorded at 250 samples / second) ecg_signal = nk.ecg_simulate(duration=30, sampling_rate=250)
Once you have a raw ECG signal in the shape of a vector (i.e., a one-dimensional array), or a list, you can use ecg_process() to process it.
Note: It is critical that you specify the correct sampling rate of your signal throughout many processing functions, as this allows NeuroKit to have a time reference.
# Automatically process the (raw) ECG signal signals, info = nk.ecg_process(ecg_signal, sampling_rate=250)
This function outputs two elements, a dataframe containing the different signals (raw, cleaned, etc.) and a dictionary containing various additional information (peaks location, …).
Extract R-peaks location#
The processing function does two important things for our purpose: 1) it cleans the signal and 2) it detects the location of the R-peaks. Let’s extract these from the output.
# Extract clean ECG and R-peaks location rpeaks = info["ECG_R_Peaks"] cleaned_ecg = signals["ECG_Clean"]
Great. We can visualize the R-peaks location in the signal to make sure it got detected correctly by marking their location in the signal.
# Visualize R-peaks in ECG signal plot = nk.events_plot(rpeaks, cleaned_ecg)
Once that we know where the R-peaks are located, we can create windows of signal around them (of a length of for instance 1 second, ranging from 400 ms before the R-peak), which we can refer to as epochs.
Segment the signal around the heart beats#
You can now epoch all these individual heart beats, synchronized by their R peaks with the ecg_segment() function.
# Plotting all the heart beats epochs = nk.ecg_segment(cleaned_ecg, rpeaks=None, sampling_rate=250, show=True)
This create a dictionary of dataframes for each ‘epoch’ (in this case, each heart beat).
This section is written for a more advanced purpose of plotting and visualizing all the heartbeats segments. The code below uses packages other than NeuroKit2 to manually set the colour gradient of the signals and to create a more interactive experience for the user - by hovering your cursor over each signal, an annotation of the signal corresponding to the heart beat index is shown.
Custom colors and legend#
Here, we define a function to create the epochs. It takes in
cleaned as the cleaned signal dataframe, and
peaks as the array of R-peaks locations.
# Define a function to create epochs def extract_heartbeats(cleaned, peaks, sampling_rate=None): heartbeats = nk.epochs_create(cleaned, events=peaks, epochs_start=-0.3, epochs_end=0.4, sampling_rate=sampling_rate) heartbeats = nk.epochs_to_df(heartbeats) return heartbeats heartbeats = extract_heartbeats(cleaned_ecg, peaks=rpeaks, sampling_rate=250) heartbeats.head()
We then pivot the dataframe so that each column corresponds to the signal values of one channel, or Label.
heartbeats_pivoted = heartbeats.pivot(index='Time', columns='Label', values='Signal') heartbeats_pivoted.head()
5 rows × 34 columns
# Prepare figure fig, ax = plt.subplots() ax.set_title("Individual Heart Beats") ax.set_xlabel("Time (seconds)") # Aesthetics labels = list(heartbeats_pivoted) labels = ['Channel ' + x for x in labels] # Set labels for each signal cmap = iter(plt.cm.YlOrRd(np.linspace(0,1, int(heartbeats["Label"].nunique())))) # Get color map lines =  # Create empty list to contain the plot of each signal for i, x, color in zip(labels, heartbeats_pivoted, cmap): line, = ax.plot(heartbeats_pivoted[x], label='%s' % i, color=color) lines.append(line)
This section of the code incorporates the aesthetics and interactivity of the plot produced. Unfortunately, the interactivity is not active in this example but it should work in your console! As you hover your cursor over each signal, annotation of the channel that produced it is shown. You will need to uncomment the code below.
Note: you need to install the
mplcursors package for the interactive part (
pip install mplcursors)
# # Import packages # import ipywidgets as widgets # from ipywidgets import interact, interact_manual # import mplcursors # # Obtain hover cursor # mplcursors.cursor(lines, hover=True, highlight=True).connect("add", lambda sel: sel.annotation.set_text(sel.artist.get_label())) # # Return figure # fig