Demo Scripts for the wfdb-python package

Run this notebook from the base directory of the git repository to access the included demo files

Documentation Site

http://wfdb.readthedocs.io/


In [1]:
from IPython.display import display
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import os
import shutil
import posixpath

import wfdb

In [3]:
# Demo 1 - Read a WFDB record using the 'rdrecord' function into a wfdb.Record object.
# Plot the signals, and show the data.
record = wfdb.rdrecord('sample-data/a103l') 
wfdb.plot_wfdb(record=record, title='Record a103l from PhysioNet Challenge 2015') 
display(record.__dict__)

# Can also read the same files hosted on PhysioNet https://physionet.org/content/challenge-2015/1.0.0
# in the /training/ database subdirectory.
record2 = wfdb.rdrecord('a103l', pn_dir='challenge-2015/training/')


{'record_name': 'a103l',
 'n_sig': 3,
 'fs': 250,
 'counter_freq': None,
 'base_counter': None,
 'sig_len': 82500,
 'base_time': None,
 'base_date': None,
 'comments': ['Asystole', 'False alarm'],
 'sig_name': ['II', 'V', 'PLETH'],
 'p_signal': array([[-0.02359597,  0.86758555,  0.48220271],
        [-0.03698082,  0.98298479,  0.5443735 ],
        [-0.06292259,  0.85979087,  0.47821229],
        ...,
        [-0.04084449,  0.7493346 ,  0.5150838 ],
        [-0.04719194,  0.7581749 ,  0.50957702],
        [-0.04677798,  0.7615019 ,  0.5028731 ]]),
 'd_signal': None,
 'e_p_signal': None,
 'e_d_signal': None,
 'file_name': ['a103l.mat', 'a103l.mat', 'a103l.mat'],
 'fmt': ['16', '16', '16'],
 'samps_per_frame': [1, 1, 1],
 'skew': [None, None, None],
 'byte_offset': [24, 24, 24],
 'adc_gain': [7247.0, 10520.0, 12530.0],
 'baseline': [0, 0, 0],
 'units': ['mV', 'mV', 'NU'],
 'adc_res': [16, 16, 16],
 'adc_zero': [0, 0, 0],
 'init_value': [-171, 9127, 6042],
 'checksum': [-27403, -301, -17391],
 'block_size': [0, 0, 0]}

In [10]:
# Demo 2 - Read certain channels and sections of the WFDB record using the simplified 'rdsamp' function
# which returns a numpy array and a dictionary. Show the data.
signals, fields = wfdb.rdsamp('sample-data/s0010_re', channels=[14, 0, 5, 10], sampfrom=100, sampto=15000)
display(signals)
display(fields)

# Can also read the same files hosted on Physionet
signals2, fields2 = wfdb.rdsamp('s0010_re', channels=[14, 0, 5, 10], sampfrom=100, sampto=15000, pn_dir='ptbdb/patient001/')


array([[ 0.0335, -0.167 , -0.237 ,  0.1165],
       [ 0.0355, -0.1615, -0.2395,  0.119 ],
       [ 0.0385, -0.168 , -0.2465,  0.116 ],
       ...,
       [-0.0445,  0.008 ,  0.033 ,  0.045 ],
       [-0.044 ,  0.0175,  0.042 ,  0.052 ],
       [-0.044 ,  0.0245,  0.0365,  0.05  ]])
{'fs': 1000,
 'sig_len': 14900,
 'n_sig': 4,
 'base_date': None,
 'base_time': None,
 'units': ['mV', 'mV', 'mV', 'mV'],
 'sig_name': ['vz', 'i', 'avf', 'v5'],
 'comments': ['age: 81',
  'sex: female',
  'ECG date: 01/10/1990',
  'Diagnose:',
  'Reason for admission: Myocardial infarction',
  'Acute infarction (localization): infero-latera',
  'Former infarction (localization): no',
  'Additional diagnoses: Diabetes mellitus',
  'Smoker: no',
  'Number of coronary vessels involved: 1',
  'Infarction date (acute): 29-Sep-90',
  'Previous infarction (1) date: n/a',
  'Previous infarction (2) date: n/a',
  'Hemodynamics:',
  'Catheterization date: 16-Oct-90',
  'Ventriculography: Akinesia inferior wall',
  'Chest X-ray: Heart size upper limit of norm',
  'Peripheral blood Pressure (syst/diast):  140/80 mmHg',
  'Pulmonary artery pressure (at rest) (syst/diast): n/a',
  'Pulmonary artery pressure (at rest) (mean): n/a',
  'Pulmonary capillary wedge pressure (at rest): n/a',
  'Cardiac output (at rest): n/a',
  'Cardiac index (at rest): n/a',
  'Stroke volume index (at rest): n/a',
  'Pulmonary artery pressure (laod) (syst/diast): n/a',
  'Pulmonary artery pressure (laod) (mean): n/a',
  'Pulmonary capillary wedge pressure (load): n/a',
  'Cardiac output (load): n/a',
  'Cardiac index (load): n/a',
  'Stroke volume index (load): n/a',
  'Aorta (at rest) (syst/diast): 160/64 cmH2O',
  'Aorta (at rest) mean: 106 cmH2O',
  'Left ventricular enddiastolic pressure: 11 cmH2O',
  'Left coronary artery stenoses (RIVA): RIVA 70% proximal to ramus diagonalis_2',
  'Left coronary artery stenoses (RCX): No stenoses',
  'Right coronary artery stenoses (RCA): No stenoses',
  'Echocardiography: n/a',
  'Therapy:',
  'Infarction date: 29-Sep-90',
  'Catheterization date: 16-Oct-90',
  'Admission date: 29-Sep-90',
  'Medication pre admission: Isosorbit-Dinitrate Digoxin Glibenclamide',
  'Start lysis therapy (hh.mm): 19:45',
  'Lytic agent: Gamma-TPA',
  'Dosage (lytic agent): 30 mg',
  'Additional medication: Heparin Isosorbit-Mononitrate ASA Diazepam',
  'In hospital medication: ASA Isosorbit-Mononitrate Ca-antagonist Amiloride+Chlorothiazide Glibenclamide Insulin',
  'Medication after discharge: ASA Isosorbit-Mononitrate Amiloride+Chlorothiazide Glibenclamide']}

In [31]:
# Demo 3 - Read a WFDB header file only (without the signals)
record = wfdb.rdheader('sample-data/drive02')
display(record.__dict__)

# Can also read the same file hosted on Physionet
record2 = wfdb.rdheader('drive02', pn_dir='drivedb')


{'record_name': 'drive02',
 'n_sig': 5,
 'fs': 15.5,
 'counter_freq': None,
 'base_counter': None,
 'sig_len': 78056,
 'base_time': None,
 'base_date': None,
 'comments': [],
 'sig_name': ['ECG', 'foot GSR', 'HR', 'marker', 'RESP'],
 'p_signal': None,
 'd_signal': None,
 'e_p_signal': None,
 'e_d_signal': None,
 'file_name': ['drive02.dat',
  'drive02.dat',
  'drive02.dat',
  'drive02.dat',
  'drive02.dat'],
 'fmt': ['16', '16', '16', '16', '16'],
 'samps_per_frame': [32, 2, 1, 1, 2],
 'skew': [None, None, None, None, None],
 'byte_offset': [None, None, None, None, None],
 'adc_gain': [1000.0, 1000.0, 1.0001, 100.0, 500.0],
 'baseline': [0, 0, 0, 0, 0],
 'units': ['mV', 'mV', 'bpm', 'mV', 'mV'],
 'adc_res': [16, 16, 16, 16, 16],
 'adc_zero': [0, 0, 0, 0, 0],
 'init_value': [-1236, 1802, 75, 0, 5804],
 'checksum': [14736, 13501, -19070, -9226, -14191],
 'block_size': [0, 0, 0, 0, 0]}

In [8]:
# Demo 4 - Read part of a WFDB annotation file into a wfdb.Annotation object, and plot the samples
annotation = wfdb.rdann('sample-data/100', 'atr', sampfrom=100000, sampto=110000)
annotation.fs = 360
wfdb.plot_wfdb(annotation=annotation, time_units='minutes')

# Can also read the same file hosted on PhysioNet 
annotation2 = wfdb.rdann('100', 'atr', sampfrom=100000, sampto=110000, pn_dir='mitdb')



In [5]:
# Demo 5 - Read a WFDB record and annotation. Plot all channels, and the annotation on top of channel 0.
record = wfdb.rdrecord('sample-data/100', sampto = 15000)
annotation = wfdb.rdann('sample-data/100', 'atr', sampto = 15000)

wfdb.plot_wfdb(record=record, annotation=annotation,
               title='Record 100 from MIT-BIH Arrhythmia Database',
               time_units='seconds')


Multiple sample/frame examples

Although there can only be one base sampling frequency per record, a single WFDB record can store multiple channels with different sampling frequencies, as long as their sampling frequencies can all be expressed by an integer multiple of a base value. This is done by using the samps_per_frame attribute in each channel, which indicates the number of samples of each channel present in each frame.

ie: To capture three signals with sampling frequencies of 120, 240, and 360 Hz, in a single record, they can be combined into a record with fs=120 and samps_per_frame = [1, 2, 3].

Reading Options

This package allows signals in records with multiple samples/frame to be read in two ways:

  1. smoothed - An uniform mxn numpy is returned as the d_signal or p_signal field. Channels with multiple samples/frame have their values averaged within each frame. This is like the behaviour of the rdsamp function of the original WFDB c package. Note that wfdb.plot_record only works if the record object has the p_signals field.
  2. expanded - A list of 1d numpy arrays is returned as the e_d_signal or e_p_signal field. All samples for each channel are returned in its respective numpy array. The arrays may have different lengths depending on their samps_per_frame values.

Set the smooth_frames (default=True) option in rdrecord to return the desired signal type.

Multisegment waveform examples

The following sections load and plots waveforms from the MIMIC matched waveform database. These waveforms have been matched to clinical data in the MIMIC Clinical database. The input records are multi-segment (made up of multiple individual WFDB records) and relatively long.

Note that these kinds of records contain segments in which certain channels are missing. matplotlib automatically zooms in on sections without Nans in individual channels but the entire durations of the signals input into plotrec are actually plotted.


In [5]:
# Demo 6 - Read the multi-segment record and plot waveforms from the MIMIC matched waveform database. 
record = wfdb.rdrecord('sample-data/multi-segment/p000878/3269321_0001')
wfdb.plot_wfdb(record=record, title='Record p000878/3269321_0001') 
display(record.__dict__)

# Can also read the same files hosted on PhysioNet (takes long to stream the many large files)
signals, fields = wfdb.rdsamp('3269321_0001', pn_dir = 'mimic3wdb/matched/p00/p000878')
wfdb.plot_items(signal=signals, fs=fields['fs'], title='Record p000878/3269321_0001')
display((signals, fields))


{'record_name': '3269321_0001',
 'n_sig': 1,
 'fs': 125,
 'counter_freq': None,
 'base_counter': None,
 'sig_len': 2000,
 'base_time': datetime.time(16, 57, 39),
 'base_date': None,
 'comments': [],
 'sig_name': ['PLETH'],
 'p_signal': array([[       nan],
        [       nan],
        [       nan],
        ...,
        [0.52156863],
        [0.51764706],
        [0.51764706]]),
 'd_signal': None,
 'e_p_signal': None,
 'e_d_signal': None,
 'file_name': ['3269321_0001.dat'],
 'fmt': ['80'],
 'samps_per_frame': [1],
 'skew': [None],
 'byte_offset': [None],
 'adc_gain': [255.0],
 'baseline': [-128],
 'units': ['NU'],
 'adc_res': [8],
 'adc_zero': [0],
 'init_value': [-128],
 'checksum': [-25757],
 'block_size': [0]}
(array([[       nan],
        [       nan],
        [       nan],
        ...,
        [0.52156863],
        [0.51764706],
        [0.51764706]]),
 {'fs': 125,
  'sig_len': 2000,
  'n_sig': 1,
  'base_date': None,
  'base_time': datetime.time(16, 57, 39),
  'units': ['NU'],
  'sig_name': ['PLETH'],
  'comments': []})

In [54]:
# Demo 7 - Read the multi-segment record and plot waveforms from the MIMIC matched waveform database.
# Notice that some channels have no valid values to plot
record = wfdb.rdrecord('sample-data/multi-segment/p000878/3269321_0001',
                       sampfrom=300, sampto=1000)
wfdb.plot_wfdb(record, title='Record p000878/3269321_0001') 
display(record.__dict__)

# Can also read the same files hosted on Physionet
record2 = wfdb.rdrecord('3269321_0001', sampfrom=300, sampto=1000,
                        pn_dir = 'mimic3wdb/matched/p00/p000878')


{'record_name': '3269321_0001',
 'n_sig': 1,
 'fs': 125,
 'counter_freq': None,
 'base_counter': None,
 'sig_len': 700,
 'base_time': datetime.time(16, 57, 41, 400000),
 'base_date': None,
 'comments': [],
 'sig_name': ['PLETH'],
 'p_signal': array([[0.43137255],
        [0.43921569],
        [0.44705882],
        [0.45490196],
        [0.4627451 ],
        [0.47058824],
        [0.4745098 ],
        [0.48235294],
        [0.48627451],
        [0.49019608],
        [0.49411765],
        [0.49411765],
        [0.49803922],
        [0.49803922],
        [0.49803922],
        [0.49803922],
        [0.49411765],
        [0.49411765],
        [0.49019608],
        [0.48627451],
        [0.48235294],
        [0.47843137],
        [0.4745098 ],
        [0.4745098 ],
        [0.47058824],
        [0.46666667],
        [0.4627451 ],
        [0.45882353],
        [0.45490196],
        [0.45490196],
        [0.45098039],
        [0.44705882],
        [0.44705882],
        [0.44313725],
        [0.44313725],
        [0.43921569],
        [0.43921569],
        [0.43529412],
        [0.43529412],
        [0.43137255],
        [0.43137255],
        [0.42745098],
        [0.42745098],
        [0.42745098],
        [0.42745098],
        [0.42352941],
        [0.42352941],
        [0.42352941],
        [0.41960784],
        [0.41960784],
        [0.41568627],
        [0.41568627],
        [0.41568627],
        [0.41568627],
        [0.41568627],
        [0.41568627],
        [0.41568627],
        [0.41568627],
        [0.41568627],
        [0.41568627],
        [0.41568627],
        [0.41568627],
        [0.41960784],
        [0.41960784],
        [0.41960784],
        [0.42352941],
        [0.42352941],
        [0.42352941],
        [0.42745098],
        [0.42745098],
        [0.43137255],
        [0.43529412],
        [0.43921569],
        [0.44705882],
        [0.45490196],
        [0.45882353],
        [0.46666667],
        [0.4745098 ],
        [0.47843137],
        [0.48235294],
        [0.48627451],
        [0.49411765],
        [0.49803922],
        [0.49803922],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.49803922],
        [0.49803922],
        [0.49411765],
        [0.49019608],
        [0.48627451],
        [0.48235294],
        [0.47843137],
        [0.4745098 ],
        [0.47058824],
        [0.46666667],
        [0.4627451 ],
        [0.4627451 ],
        [0.45882353],
        [0.45490196],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.44705882],
        [0.44705882],
        [0.44705882],
        [0.44313725],
        [0.44313725],
        [0.44313725],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.43529412],
        [0.43137255],
        [0.43137255],
        [0.42745098],
        [0.42745098],
        [0.42352941],
        [0.42352941],
        [0.42352941],
        [0.42352941],
        [0.42352941],
        [0.42352941],
        [0.42745098],
        [0.42745098],
        [0.42745098],
        [0.42745098],
        [0.42745098],
        [0.42745098],
        [0.42745098],
        [0.42745098],
        [0.42745098],
        [0.42745098],
        [0.43137255],
        [0.43921569],
        [0.45490196],
        [0.46666667],
        [0.4745098 ],
        [0.48235294],
        [0.49411765],
        [0.50588235],
        [0.52156863],
        [0.53333333],
        [0.54509804],
        [0.55686275],
        [0.56862745],
        [0.57647059],
        [0.58431373],
        [0.59215686],
        [0.59607843],
        [0.6       ],
        [0.60392157],
        [0.60392157],
        [0.60784314],
        [0.60784314],
        [0.60392157],
        [0.60392157],
        [0.6       ],
        [0.59607843],
        [0.59215686],
        [0.58431373],
        [0.57647059],
        [0.56862745],
        [0.56078431],
        [0.55686275],
        [0.54901961],
        [0.54509804],
        [0.5372549 ],
        [0.53333333],
        [0.52941176],
        [0.5254902 ],
        [0.5254902 ],
        [0.52156863],
        [0.52156863],
        [0.52156863],
        [0.51764706],
        [0.51764706],
        [0.51372549],
        [0.51372549],
        [0.50980392],
        [0.50588235],
        [0.50196078],
        [0.50196078],
        [0.49803922],
        [0.49411765],
        [0.49019608],
        [0.48235294],
        [0.47843137],
        [0.4745098 ],
        [0.47058824],
        [0.46666667],
        [0.4627451 ],
        [0.45882353],
        [0.45490196],
        [0.45490196],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45490196],
        [0.4627451 ],
        [0.47058824],
        [0.47843137],
        [0.49019608],
        [0.50196078],
        [0.50980392],
        [0.51764706],
        [0.5254902 ],
        [0.53333333],
        [0.54117647],
        [0.54901961],
        [0.55294118],
        [0.55686275],
        [0.55686275],
        [0.55686275],
        [0.55686275],
        [0.55294118],
        [0.54509804],
        [0.5372549 ],
        [0.53333333],
        [0.52941176],
        [0.52156863],
        [0.51764706],
        [0.51372549],
        [0.50588235],
        [0.50196078],
        [0.49411765],
        [0.49019608],
        [0.48627451],
        [0.47843137],
        [0.47843137],
        [0.4745098 ],
        [0.47058824],
        [0.47058824],
        [0.46666667],
        [0.4627451 ],
        [0.4627451 ],
        [0.45882353],
        [0.45490196],
        [0.45490196],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.44705882],
        [0.44705882],
        [0.44313725],
        [0.44313725],
        [0.43921569],
        [0.43921569],
        [0.43529412],
        [0.43137255],
        [0.43137255],
        [0.43137255],
        [0.43137255],
        [0.43137255],
        [0.43137255],
        [0.43529412],
        [0.43529412],
        [0.43921569],
        [0.43921569],
        [0.44313725],
        [0.44705882],
        [0.45098039],
        [0.45490196],
        [0.4627451 ],
        [0.47058824],
        [0.47843137],
        [0.48627451],
        [0.50196078],
        [0.51372549],
        [0.52156863],
        [0.53333333],
        [0.54117647],
        [0.54901961],
        [0.55686275],
        [0.56470588],
        [0.56862745],
        [0.57254902],
        [0.57254902],
        [0.57647059],
        [0.57647059],
        [0.57647059],
        [0.57254902],
        [0.57254902],
        [0.56862745],
        [0.56470588],
        [0.56470588],
        [0.56078431],
        [0.55686275],
        [0.54901961],
        [0.54509804],
        [0.5372549 ],
        [0.53333333],
        [0.52941176],
        [0.52156863],
        [0.51764706],
        [0.51372549],
        [0.50588235],
        [0.50196078],
        [0.50196078],
        [0.49803922],
        [0.49411765],
        [0.49019608],
        [0.48627451],
        [0.48235294],
        [0.47843137],
        [0.4745098 ],
        [0.47058824],
        [0.4627451 ],
        [0.45882353],
        [0.45490196],
        [0.45098039],
        [0.44705882],
        [0.44705882],
        [0.44313725],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.43529412],
        [0.43137255],
        [0.43137255],
        [0.42745098],
        [0.42352941],
        [0.42352941],
        [0.41960784],
        [0.41568627],
        [0.41176471],
        [0.40784314],
        [0.40784314],
        [0.40392157],
        [0.40392157],
        [0.4       ],
        [0.4       ],
        [0.40392157],
        [0.40784314],
        [0.41176471],
        [0.41960784],
        [0.43137255],
        [0.43921569],
        [0.45098039],
        [0.45882353],
        [0.47058824],
        [0.47843137],
        [0.49019608],
        [0.49803922],
        [0.50588235],
        [0.50980392],
        [0.51764706],
        [0.51764706],
        [0.52156863],
        [0.52156863],
        [0.52156863],
        [0.52156863],
        [0.52156863],
        [0.51764706],
        [0.51764706],
        [0.50980392],
        [0.50588235],
        [0.50196078],
        [0.49803922],
        [0.49019608],
        [0.48235294],
        [0.47843137],
        [0.47058824],
        [0.46666667],
        [0.4627451 ],
        [0.45882353],
        [0.45882353],
        [0.45490196],
        [0.45490196],
        [0.45490196],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.44705882],
        [0.44705882],
        [0.44313725],
        [0.44313725],
        [0.44313725],
        [0.44705882],
        [0.44705882],
        [0.44705882],
        [0.44705882],
        [0.44705882],
        [0.44313725],
        [0.44313725],
        [0.44313725],
        [0.43921569],
        [0.43921569],
        [0.44313725],
        [0.44313725],
        [0.44313725],
        [0.44313725],
        [0.44313725],
        [0.44313725],
        [0.44313725],
        [0.44313725],
        [0.44705882],
        [0.44705882],
        [0.45098039],
        [0.45490196],
        [0.45490196],
        [0.45882353],
        [0.46666667],
        [0.47058824],
        [0.47843137],
        [0.48627451],
        [0.49411765],
        [0.50196078],
        [0.50980392],
        [0.51372549],
        [0.52156863],
        [0.5254902 ],
        [0.52941176],
        [0.53333333],
        [0.5372549 ],
        [0.5372549 ],
        [0.5372549 ],
        [0.5372549 ],
        [0.53333333],
        [0.52941176],
        [0.5254902 ],
        [0.51764706],
        [0.50980392],
        [0.49803922],
        [0.48627451],
        [0.4745098 ],
        [0.4627451 ],
        [0.44705882],
        [0.42745098],
        [0.41176471],
        [0.39215686],
        [0.37254902],
        [0.35686275],
        [0.3372549 ],
        [0.3254902 ],
        [0.30980392],
        [0.29803922],
        [0.29019608],
        [0.28627451],
        [0.28235294],
        [0.28235294],
        [0.28235294],
        [0.29019608],
        [0.29803922],
        [0.31372549],
        [0.3254902 ],
        [0.34117647],
        [0.35686275],
        [0.37647059],
        [0.39215686],
        [0.40784314],
        [0.42352941],
        [0.43921569],
        [0.45490196],
        [0.47058824],
        [0.48627451],
        [0.49803922],
        [0.51372549],
        [0.52156863],
        [0.53333333],
        [0.54117647],
        [0.54509804],
        [0.55294118],
        [0.55686275],
        [0.56078431],
        [0.56470588],
        [0.56862745],
        [0.56862745],
        [0.57254902],
        [0.57254902],
        [0.57647059],
        [0.58039216],
        [0.58431373],
        [0.58823529],
        [0.59607843],
        [0.6       ],
        [0.60392157],
        [0.60784314],
        [0.61568627],
        [0.61960784],
        [0.62352941],
        [0.62745098],
        [0.63137255],
        [0.63529412],
        [0.63529412],
        [0.63529412],
        [0.63529412],
        [0.63529412],
        [0.63137255],
        [0.63137255],
        [0.62745098],
        [0.62352941],
        [0.61960784],
        [0.61568627],
        [0.60784314],
        [0.6       ],
        [0.59607843],
        [0.58823529],
        [0.58039216],
        [0.57647059],
        [0.56862745],
        [0.56470588],
        [0.56078431],
        [0.55294118],
        [0.54901961],
        [0.54509804],
        [0.54509804],
        [0.54117647],
        [0.5372549 ],
        [0.53333333],
        [0.5254902 ],
        [0.52156863],
        [0.51764706],
        [0.51372549],
        [0.50980392],
        [0.50980392],
        [0.50588235],
        [0.50196078],
        [0.49803922],
        [0.49019608],
        [0.48627451],
        [0.47843137],
        [0.4745098 ],
        [0.46666667],
        [0.4627451 ],
        [0.45882353],
        [0.45882353],
        [0.45490196],
        [0.45490196],
        [0.45098039],
        [0.45098039],
        [0.44705882],
        [0.44705882],
        [0.44705882],
        [0.44705882],
        [0.44313725],
        [0.44313725],
        [0.44313725],
        [0.44313725],
        [0.44705882],
        [0.44705882],
        [0.44705882],
        [0.45098039],
        [0.45490196],
        [0.45882353],
        [0.46666667],
        [0.4745098 ],
        [0.47843137],
        [0.48627451],
        [0.49411765],
        [0.50196078],
        [0.50980392],
        [0.51372549],
        [0.52156863],
        [0.5254902 ],
        [0.52941176],
        [0.52941176],
        [0.5254902 ],
        [0.5254902 ],
        [0.52156863],
        [0.52156863],
        [0.51764706],
        [0.51372549],
        [0.51372549],
        [0.50980392],
        [0.50588235],
        [0.50196078],
        [0.49803922],
        [0.49411765],
        [0.48627451],
        [0.48235294],
        [0.47843137],
        [0.4745098 ],
        [0.47058824],
        [0.46666667],
        [0.4627451 ],
        [0.4627451 ],
        [0.45882353],
        [0.45882353],
        [0.45882353],
        [0.45882353],
        [0.45882353],
        [0.45490196],
        [0.45490196],
        [0.45490196],
        [0.45490196],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.45098039],
        [0.44705882],
        [0.44705882],
        [0.44313725],
        [0.44313725],
        [0.44313725],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.43921569],
        [0.44313725],
        [0.44705882],
        [0.45098039],
        [0.45490196],
        [0.4627451 ],
        [0.47058824],
        [0.47843137],
        [0.49019608],
        [0.49803922],
        [0.50588235],
        [0.51372549],
        [0.52156863],
        [0.5254902 ],
        [0.52941176],
        [0.53333333],
        [0.5372549 ],
        [0.5372549 ],
        [0.54117647],
        [0.54117647],
        [0.5372549 ],
        [0.5372549 ],
        [0.53333333],
        [0.53333333],
        [0.52941176],
        [0.52941176],
        [0.5254902 ],
        [0.5254902 ],
        [0.52156863],
        [0.52156863],
        [0.52156863],
        [0.51764706],
        [0.51764706],
        [0.51372549],
        [0.51372549],
        [0.51372549],
        [0.51372549],
        [0.51372549],
        [0.51372549],
        [0.51372549],
        [0.51372549],
        [0.51372549],
        [0.50980392],
        [0.50980392],
        [0.50980392],
        [0.50588235],
        [0.50588235],
        [0.50588235],
        [0.50588235],
        [0.50588235],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50196078],
        [0.50588235],
        [0.50588235],
        [0.50980392],
        [0.51372549]]),
 'd_signal': None,
 'e_p_signal': None,
 'e_d_signal': None,
 'file_name': ['3269321_0001.dat'],
 'fmt': ['80'],
 'samps_per_frame': [1],
 'skew': [None],
 'byte_offset': [None],
 'adc_gain': [255.0],
 'baseline': [-128],
 'units': ['NU'],
 'adc_res': [8],
 'adc_zero': [0],
 'init_value': [-18],
 'checksum': [62211],
 'block_size': [0]}

In [42]:
# Demo 8 - Read a WFDB record in which one channel has multiple samples/frame. Return a smoothed uniform array.
record = wfdb.rdrecord('sample-data/test01_00s_frame')
wfdb.plot_wfdb(record)



In [44]:
from IPython.display import display
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import os
import shutil
import posixpath

import wfdb

In [55]:
# Demo 9 - Read a WFDB record in which one channel has multiple samples/frame. Return a list of all the expanded samples.
record = wfdb.rdrecord('sample-data/test01_00s_frame', smooth_frames=False)

display(record.e_p_signal)
# Show that different channels have different lengths. Channel 1 has 2 samples/frame, hence has 2x as many samples.
print([len(s) for s in record.e_p_signal])

# wfdb.plotrec doesn't work because the Record object is missing its p_signals field.


[array([ 0.1 ,  0.11,  0.13, ..., -0.27, -0.27, -0.26]),
 array([-0.08, -0.57, -0.06, ...,  0.13, -0.18,  0.12]),
 array([-0.66, -0.66, -0.67, ...,  0.15,  0.15,  0.16])]
[4000, 8000, 4000]

Writing Records and Annotations


In [2]:


In [6]:
# Demo 10 - Read a WFDB record's digital samples and create a copy via the wrsamp() instance method of the Record object.

# Read a record as a Record object.
record = wfdb.rdrecord('sample-data/100', physical=False)
record.record_name = '100x'

# Call the instance method of the object
record.wrsamp()

# The new file can be read
record_x = wfdb.rdrecord('100x')

# Cleanup: delete the created files
# os.remove('100x.hea')
# os.remove('100.dat')

In [8]:
# Demo 11 - Write a WFDB record without using a Record object via the gateway wrsamp function.
# This is the basic way to write physical signals to a WFDB file. 

# Read part of a record from Physionet
sig, fields = wfdb.rdsamp('a103l', sampfrom=50000, channels=[0,1], pn_dir='challenge-2015/training')

# Call the gateway wrsamp function, manually inserting fields as function input parameters
wfdb.wrsamp('ecg-record', fs=250, units=['mV', 'mV'], sig_name=['I', 'II'], p_signal=sig, fmt=['16', '16'])

# The new file can be read
record = wfdb.rdrecord('ecg-record')

# Cleanup: delete the created files
# os.remove('ecg-record.hea')
# os.remove('ecg-record.dat')

In [9]:
wfdb.plot_wfdb(record)



In [7]:
from IPython.display import display
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import os
import shutil
import posixpath


import wfdb

In [10]:
# Demo 12 - Write a WFDB record with multiple samples/frame in a channel

# Read a record as a Record object.
record = wfdb.rdrecord('sample-data/test01_00s_frame', physical=False, smooth_frames=False)
record.record_name = 'test01_00s_framex'

# Call the instance method of the object with expanded=True to write the record using the e_d_signal field
record.wrsamp(expanded=True)

# The new file can be read
recordx = wfdb.rdrecord('test01_00s_framex')

# Cleanup: deleted the created files
# os.remove('test01_00s_framex.hea')
# os.remove('test01_00s.dat')

In [11]:
# Demo 13 - Read a WFDB annotation file and create a copy via the wrann() instance method
# of the Annotation object

# Read an annotation from Physionet
annotation = wfdb.rdann('sample-data/100', 'atr')
annotation.extension = 'cpy'

# Call the instance method of the object
annotation.wrann()

# The new file can be read
annotation_copy = wfdb.rdann('100', 'cpy')

# Cleanup: deleted the created files
# os.remove('100.cpy')

In [12]:
# Demo 14 - Write a WFDB annotation file without using an Annotator
# object via the gateway wrann function.

# Read an annotation as an Annotation object
annotation = wfdb.rdann('b001', 'atr', pn_dir='cebsdb')

# Call the gateway wrann function, manually inserting fields as function input parameters
wfdb.wrann('b001', 'cpy', annotation.sample, annotation.symbol)

# The new file can be read
annotation_copy = wfdb.rdann('b001', 'cpy')

# Cleanup: deleted the created files
# os.remove('b001.cpy')

In [13]:
# Demo 15 - View the standard WFDB annotation labels
wfdb.show_ann_labels()


label_store symbol                                    description
0             0                              Not an actual annotation
1             1      N                                    Normal beat
2             2      L                  Left bundle branch block beat
3             3      R                 Right bundle branch block beat
4             4      a                Aberrated atrial premature beat
5             5      V              Premature ventricular contraction
6             6      F          Fusion of ventricular and normal beat
7             7      J              Nodal (junctional) premature beat
8             8      A                   Atrial premature contraction
9             9      S     Premature or ectopic supraventricular beat
10           10      E                        Ventricular escape beat
11           11      j                 Nodal (junctional) escape beat
12           12      /                                     Paced beat
13           13      Q                            Unclassifiable beat
14           14      ~                          Signal quality change
16           16      |                     Isolated QRS-like artifact
18           18      s                                      ST change
19           19      T                                  T-wave change
20           20      *                                        Systole
21           21      D                                       Diastole
22           22      "                             Comment annotation
23           23      =                         Measurement annotation
24           24      p                                    P-wave peak
25           25      B              Left or right bundle branch block
26           26      ^                      Non-conducted pacer spike
27           27      t                                    T-wave peak
28           28      +                                  Rhythm change
29           29      u                                    U-wave peak
30           30      ?                                       Learning
31           31      !                       Ventricular flutter wave
32           32      [      Start of ventricular flutter/fibrillation
33           33      ]        End of ventricular flutter/fibrillation
34           34      e                             Atrial escape beat
35           35      n                   Supraventricular escape beat
36           36      @  Link to external data (aux_note contains URL)
37           37      x             Non-conducted P-wave (blocked APB)
38           38      f                Fusion of paced and normal beat
39           39      (                                 Waveform onset
40           40      )                                   Waveform end
41           41      r       R-on-T premature ventricular contraction

Downloading Content from Physionet

  • The downloads are made via http
  • See the above demos for examples on streaming WFDB files stored in PhysioNet without downloading them to local disk
  • PhysioNet has rsync modules for downloading entire databases for users who have access to rsync.

In [2]:
# Demo 16 - List the PhysioNet Databases

dbs = wfdb.get_dbs()
display(dbs)


[['aami-ec13', 'ANSI/AAMI EC13 Test Waveforms'],
 ['adfecgdb', 'Abdominal and Direct Fetal ECG Database'],
 ['afdb', 'MIT-BIH Atrial Fibrillation Database'],
 ['afpdb', 'PAF Prediction Challenge Database'],
 ['aftdb', 'AF Termination Challenge Database'],
 ['ahadb', 'AHA Database Sample Excluded Record'],
 ['apnea-ecg', 'Apnea-ECG Database'],
 ['bidmc', 'BIDMC PPG and Respiration Dataset'],
 ['bpssrat', 'Blood Pressure in Salt-Sensitive Dahl Rats'],
 ['capslpdb', 'CAP Sleep Database'],
 ['cdb', 'MIT-BIH ECG Compression Test Database'],
 ['cebsdb', 'Combined measurement of ECG, Breathing and Seismocardiograms'],
 ['cerebral-vasoreg-diabetes', 'Cerebral Vasoregulation in Diabetes'],
 ['charisdb', 'CHARIS database'],
 ['chbmit', 'CHB-MIT Scalp EEG Database'],
 ['chf2db', 'Congestive Heart Failure RR Interval Database'],
 ['chfdb', 'BIDMC Congestive Heart Failure Database'],
 ['crisdb', 'CAST RR Interval Sub-Study Database'],
 ['ct-ich',
  'Computed Tomography Images for Intracranial Hemorrhage Detection and Segmentation'],
 ['ct-ich',
  'Computed Tomography Images for Intracranial Hemorrhage Detection and Segmentation'],
 ['ct-ich',
  'Computed Tomography Images for Intracranial Hemorrhage Detection and Segmentation'],
 ['ct-ich',
  'Computed Tomography Images for Intracranial Hemorrhage Detection and Segmentation'],
 ['ctu-uhb-ctgdb', 'CTU-CHB Intrapartum Cardiotocography Database'],
 ['cudb', 'CU Ventricular Tachyarrhythmia Database'],
 ['cuiless16', 'CUILESS2016'],
 ['culm', 'Complex Upper-Limb Movements'],
 ['cves', 'Cerebral Vasoregulation in Elderly with Stroke'],
 ['deidentifiedmedicaltext', 'Deidentified Medical Text'],
 ['drivedb', 'Stress Recognition in Automobile Drivers'],
 ['earh', 'Evoked Auditory Responses in Heading Impaired'],
 ['earndb', 'Evoked Auditory Responses in Normals'],
 ['ecgcipa', 'CiPA ECG Validation Study'],
 ['ecgdmmld',
  'ECG Effects of Dofetilide, Moxifloxacin, Dofetilide+Mexiletine, Dofetilide+Lidocaine and Moxifloxacin+Diltiazem'],
 ['ecgiddb', 'ECG-ID Database'],
 ['ecgrdvq',
  'ECG Effects of Ranolazine, Dofetilide, Verapamil, and Quinidine'],
 ['edb', 'European ST-T Database'],
 ['eegmat', 'EEG During Mental Arithmetic Tasks'],
 ['eegmmidb', 'EEG Motor Movement/Imagery Dataset'],
 ['ehgdb', 'Icelandic 16-electrode Electrohysterogram Database'],
 ['eicu-crd', 'eICU Collaborative Research Database'],
 ['eicu-crd-demo', 'eICU Collaborative Research Database Demo'],
 ['emgdb', 'Examples of Electromyograms'],
 ['erpbci', 'ERP-based Brain-Computer Interface recordings'],
 ['excluded', 'Recordings excluded from the NSR DB'],
 ['fantasia', 'Fantasia Database'],
 ['fecgsyndb', 'Fetal ECG Synthetic Database'],
 ['fpcgdb', 'Fetal PCG Database'],
 ['gait-maturation-db', 'Gait Maturation Database'],
 ['gaitdb', 'Gait in Aging and Disease Database'],
 ['gaitndd', 'Gait in Neurodegenerative Disease Database'],
 ['gaitpdb', "Gait in Parkinson's Disease"],
 ['hbedb', 'Human Balance Evaluation Database'],
 ['iafdb', 'Intracardiac Atrial Fibrillation Database'],
 ['images', 'Samples of MR Images'],
 ['incartdb', 'St Petersburg INCART 12-lead Arrhythmia Database'],
 ['inipdmsa',
  'Safety and Preliminary Efficacy of Intranasal Insulin for Cognitive Impairment in Parkinson Disease and Multiple System Atrophy'],
 ['kinematic-actors-emotions',
  'Kinematic dataset of actors expressing emotions'],
 ['ltafdb', 'Long Term AF Database'],
 ['ltdb', 'MIT-BIH Long-Term ECG Database'],
 ['ltmm', 'Long Term Movement Monitoring Database'],
 ['ltrsvp', 'EEG Signals from an RSVP Task'],
 ['ltstdb', 'Long Term ST Database'],
 ['macecgdb', 'Motion Artifact Contaminated ECG Database'],
 ['maternal-visceral-adipose',
  'Visceral adipose tissue measurements during pregnancy'],
 ['meditation', 'Heart Rate Oscillations during Meditation'],
 ['mednli',
  'MedNLI - A Natural Language Inference Dataset For The Clinical Domain'],
 ['mednli-bionlp19', 'MedNLI for Shared Task at ACL BioNLP 2019'],
 ['mednli-bionlp19', 'MedNLI for Shared Task at ACL BioNLP 2019'],
 ['mghdb', 'MGH/MF Waveform Database'],
 ['mimic-cxr', 'MIMIC-CXR Database'],
 ['mimic-cxr', 'MIMIC-CXR Database'],
 ['mimic-cxr-jpg', 'MIMIC-CXR-JPG - chest radiographs with structured labels'],
 ['mimic3wdb', 'MIMIC-III Waveform Database'],
 ['mimic3wdb-matched', 'MIMIC-III Waveform Database Matched Subset'],
 ['mimicdb', 'MIMIC Database'],
 ['mimiciii', 'MIMIC-III Clinical Database'],
 ['mimiciii-demo', 'MIMIC-III Clinical Database Demo'],
 ['mitdb', 'MIT-BIH Arrhythmia Database'],
 ['mmgdb', 'MMG Database'],
 ['motion-artifact', 'Motion Artifact Contaminated fNIRS and EEG Data'],
 ['mssvepdb', 'MAMEM SSVEP Database'],
 ['mvtdb', 'Spontaneous Ventricular Tachyarrhythmia Database'],
 ['nesfdb', 'Noise Enhancement of Sensorimotor Function'],
 ['nifeadb', 'Non-Invasive Fetal ECG Arrhythmia Database'],
 ['nifecgdb', 'Non-Invasive Fetal ECG Database'],
 ['noneeg', 'Non-EEG Dataset for Assessment of Neurological Status'],
 ['nqmitcsxpd', 'neuroQWERTY MIT-CSXPD Dataset'],
 ['nsr2db', 'Normal Sinus Rhythm RR Interval Database'],
 ['nsrdb', 'MIT-BIH Normal Sinus Rhythm Database'],
 ['nstdb', 'MIT-BIH Noise Stress Test Database'],
 ['ob1db', 'OB-1 Fetal ECG Database'],
 ['osv', 'Pattern Analysis of Oxygen Saturation Variability'],
 ['phdsm', 'Permittivity of Healthy and Diseased Skeletal Muscle'],
 ['phdsm', 'Permittivity of Healthy and Diseased Skeletal Muscle'],
 ['phenotype-annotations-mimic',
  'Phenotype Annotations for Patient Notes in the MIMIC-III Database'],
 ['physiozoo', 'PhysioZoo - mammalian NSR databases'],
 ['picdb', 'Paediatric Intensive Care database'],
 ['picsdb', 'Preterm Infant Cardio-Respiratory Signals Database'],
 ['plantar', 'Modulation of Plantar Pressure and Muscle During Gait'],
 ['pmd', 'A Pressure Map Dataset for In-bed Posture Classification'],
 ['prcp', 'Physiologic Response to Changes in Posture'],
 ['ptb-xl', 'PTB-XL, a large publicly available electrocardiography dataset'],
 ['ptb-xl', 'PTB-XL, a large publicly available electrocardiography dataset'],
 ['ptbdb', 'PTB Diagnostic ECG Database'],
 ['pwave', 'MIT-BIH Arrhythmia Database P-Wave Annotations'],
 ['qde', 'Quantitative Dehydration Estimation'],
 ['qtdb', 'QT Database'],
 ['rvmh1', 'Response to Valsalva Maneuver in Humans'],
 ['santa-fe', 'Santa Fe Time Series Competition Data Set B'],
 ['sddb', 'Sudden Cardiac Death Holter Database'],
 ['sgamp', 'Squid Giant Axon Membrane Potential'],
 ['shareedb',
  'Smart Health for Assessing the Risk of Events via ECG Database'],
 ['shhpsgdb', 'Sleep Heart Health Study PSG Database'],
 ['simfpcgdb', 'Simulated Fetal Phonocardiograms'],
 ['sleep-accel',
  'Motion and heart rate from a wrist-worn wearable and labeled sleep from polysomnography'],
 ['sleep-edf', 'Sleep-EDF Database'],
 ['sleep-edfx', 'Sleep-EDF Database Expanded'],
 ['sleepbrl', 'Sleep Bioradiolocation Database'],
 ['slpdb', 'MIT-BIH Polysomnographic Database'],
 ['staffiii', 'STAFF III Database'],
 ['stdb', 'MIT-BIH ST Change Database'],
 ['sufhsdb', 'Shiraz University Fetal Heart Sounds Database'],
 ['svdb', 'MIT-BIH Supraventricular Arrhythmia Database'],
 ['szdb', 'Post-Ictal Heart Rate Oscillations in Partial Epilepsy'],
 ['taichidb', 'Tai Chi, Physiological Complexity, and Healthy Aging - Gait'],
 ['tappy', 'Tappy Keystroke Data'],
 ['tns', 'Surrogate Data with Correlations, Trends, and Nonstationarities'],
 ['tpehgdb', 'Term-Preterm EHG Database'],
 ['tpehgt', 'Term-Preterm EHG DataSet with Tocogram'],
 ['tremordb', 'Effect of Deep Brain Stimulation on Parkinsonian Tremor'],
 ['twadb', 'T-Wave Alternans Challenge Database'],
 ['ucddb',
  "St. Vincent's University Hospital / University College Dublin Sleep Apnea Database"],
 ['umwdb', 'Long-term Recordings of Gait Dynamics'],
 ['unicaprop', 'UniCA ElectroTastegram Database (PROP)'],
 ['vfdb', 'MIT-BIH Malignant Ventricular Ectopy Database'],
 ['videopulse', 'Video Pulse Signals in Stationary and Motion Conditions'],
 ['voiced', 'VOice ICar fEDerico II Database'],
 ['wctecgdb', 'Wilson Central Terminal ECG Database'],
 ['wctecgdb', 'Wilson Central Terminal ECG Database'],
 ['wrist', 'Wrist PPG During Exercise']]

In [4]:
# Demo 17 - Download all the WFDB records and annotations from a small PhysioNet Database

# Make a temporary download directory in your current working directory
cwd = os.getcwd()
dl_dir = os.path.join(cwd, 'tmp_dl_dir')

# Download all the WFDB content
wfdb.dl_database('ahadb', dl_dir=dl_dir)

# Display the downloaded content in the folder
display(os.listdir(dl_dir))

# Cleanup: delete the downloaded directory
# shutil.rmtree(dl_dir)


Generating record list for: 0001
Generating record list for: 0201
Generating list of all files for: 0001
Generating list of all files for: 0201
Created local base download directory: /Users/lucasmc/Documents/wfdb-python/tmp_dl_dir
Downloading files...
Finished downloading files
['0001.dat', '0201.dat', '0001.hea', '0201.hea', '0201.atr', '0001.atr']

In [5]:
# Demo 18 - Download specified files from a PhysioNet database

# The files to download
file_list = ['STAFF-Studies-bibliography-2016.pdf',
             'data/001a.hea',
             'data/001a.dat',
             'data/001b.hea',
             'data/001b.dat']

# Make a temporary download directory in your current working directory
cwd = os.getcwd()
dl_dir = os.path.join(cwd, 'tmp_dl_dir')

# Download the listed files
wfdb.dl_files('staffiii', dl_dir, file_list)

# Display the downloaded content in the folder
display(os.listdir(dl_dir))
display(os.listdir(os.path.join(dl_dir, 'data')))

# Cleanup: delete the downloaded directory
# shutil.rmtree(dl_dir)


Downloading files...
Finished downloading files
['STAFF-Studies-bibliography-2016.pdf',
 '0001.dat',
 '0201.dat',
 '0001.hea',
 '0201.hea',
 '0201.atr',
 '0001.atr',
 'data']
['001b.dat', '001a.dat', '001b.hea', '001a.hea']

ECG Processing


In [20]:
import wfdb
from wfdb import processing

In [21]:
# Demo 19 - Use the GQRS detection algorithm and correct the peaks

def peaks_hr(sig, peak_inds, fs, title, figsize=(20, 10), saveto=None):
    "Plot a signal with its peaks and heart rate"
    # Calculate heart rate
    hrs = processing.hr.compute_hr(sig_len=sig.shape[0], qrs_inds=peak_inds, fs=fs)
    
    N = sig.shape[0]
    
    fig, ax_left = plt.subplots(figsize=figsize)
    ax_right = ax_left.twinx()
    
    ax_left.plot(sig, color='#3979f0', label='Signal')
    ax_left.plot(peak_inds, sig[peak_inds], 'rx', marker='x', 
                 color='#8b0000', label='Peak', markersize=12)
    ax_right.plot(np.arange(N), hrs, label='Heart rate', color='m', linewidth=2)

    ax_left.set_title(title)

    ax_left.set_xlabel('Time (ms)')
    ax_left.set_ylabel('ECG (mV)', color='#3979f0')
    ax_right.set_ylabel('Heart rate (bpm)', color='m')
    # Make the y-axis label, ticks and tick labels match the line color.
    ax_left.tick_params('y', colors='#3979f0')
    ax_right.tick_params('y', colors='m')
    if saveto is not None:
        plt.savefig(saveto, dpi=600)
    plt.show()

# Load the WFDB record and the physical samples
record = wfdb.rdrecord('sample-data/100', sampfrom=0, sampto=10000, channels=[0])

# Use the GQRS algorithm to detect QRS locations in the first channel
qrs_inds = processing.qrs.gqrs_detect(sig=record.p_signal[:,0], fs=record.fs)

# Plot results
peaks_hr(sig=record.p_signal, peak_inds=qrs_inds, fs=record.fs,
         title="GQRS peak detection on record 100")
    
# Correct the peaks shifting them to local maxima
min_bpm = 20
max_bpm = 230
#min_gap = record.fs * 60 / min_bpm
# Use the maximum possible bpm as the search radius
search_radius = int(record.fs * 60 / max_bpm)
corrected_peak_inds = processing.peaks.correct_peaks(record.p_signal[:,0], 
                                                     peak_inds=qrs_inds,
                                                     search_radius=search_radius, 
                                                     smooth_window_size=150)

# Display results
print('Corrected GQRS detected peak indices:', sorted(corrected_peak_inds))
peaks_hr(sig=record.p_signal, peak_inds=sorted(corrected_peak_inds), fs=record.fs,
         title="Corrected GQRS peak detection on sampledata/100")


Corrected GQRS detected peak indices: [370, 663, 947, 1231, 1515, 1809, 2045, 2403, 2706, 2998, 3283, 3560, 3863, 4171, 4466, 4765, 5061, 5347, 5634, 5919, 6215, 6527, 6824, 7106, 7393, 7670, 7953, 8246, 8539, 8837, 9142, 9432, 9710]

In [6]:
# Demo 20 - Use the XQRS detection algorithm and compare results to reference annotations
import wfdb
from wfdb import processing
sig, fields = wfdb.rdsamp('sample-data/100', channels=[0], sampto=15000)
ann_ref = wfdb.rdann('sample-data/100','atr', sampto=15000)

# Run QRS detection on signal
xqrs = processing.XQRS(sig=sig[:,0], fs=fields['fs'])
xqrs.detect()
# Alternatively, use the gateway function to get the QRS indices directly
# qrs_inds = processing.xqrs_detect(sig=sig[:,0], fs=fields['fs'])

# Compare detected QRS complexes to reference annotation.
# Note, first sample in 100.atr is not a QRS.
comparitor = processing.compare_annotations(ref_sample=ann_ref.sample[1:],
                                            test_sample=xqrs.qrs_inds,
                                            window_width=int(0.1 * fields['fs']),
                                            signal=sig[:,0])

# Print and plot the results
comparitor.print_summary()
comparitor.plot(title='xqrs detected QRS vs reference annotations')


Learning initial signal parameters...
Found 8 beats during learning. Initializing using learned parameters
Running QRS detection...
QRS detection complete.
51 reference annotations, 51 test annotations

True Positives (matched samples): 51
False Positives (unmatched test samples): 0
False Negatives (unmatched reference samples): 0

Sensitivity: 1.0000 (51/51)
Positive Predictivity: 1.0000 (51/51)

In [7]:
# Cleanup for all demos
for file in ['100x.hea', '100.dat',  # demo 10
             'ecg-record.hea', 'ecg-record.dat',  # demo 11 
             'test01_00s_framex.hea', 'test01_00s.dat',  # demo 12
             '100.cpy',  # demo 13
             'b001.cpy',  # demo 14
            ]:
    if os.path.isfile(file):
        os.remove(file)

dl_dir = os.path.join(cwd, 'tmp_dl_dir')  # demo 17, 18
if os.path.isdir(dl_dir):
    shutil.rmtree(dl_dir)

In [8]:
import wfdb
record_no_skew = wfdb.rdrecord('sample-data/test01_00s_skewframe',
                               physical=False,
                               smooth_frames=False, ignore_skew=True)
record_no_skew.wrsamp(expanded=True)

In [9]:
import numpy as np
int_types = (int, np.int64, np.int32, np.int16, np.int8)

int_types[0]('10')


Out[9]:
10