Source code for heartpy.visualizeutils

'''
Functions that help visualize results
'''

import os

import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
import numpy as np

from . import config

__all__ = ['plotter',
           'segment_plotter',
           'plot_poincare',
           'plot_breathing']

[docs]def plotter(working_data, measures, show=True, title='Heart Rate Signal Peak Detection', moving_average=False): # pragma: no cover '''plots the analysis results. Function that uses calculated measures and data stored in the working_data{} and measures{} dict objects to visualise the fitted peak detection solution. Parameters ---------- working_data : dict dictionary object that contains all heartpy's working data (temp) objects. will be created if not passed to function measures : dict dictionary object used by heartpy to store computed measures. Will be created if not passed to function show : bool when False, function will return a plot object rather than display the results. default : True title : string title for the plot. default : "Heart Rate Signal Peak Detection" moving_average : bool whether to display the moving average on the plot. The moving average is used for peak fitting. default: False Returns ------- out : matplotlib plot object only returned if show == False. Examples -------- First let's load and analyse some data to visualise >>> import heartpy as hp >>> data, _ = hp.load_exampledata(0) >>> wd, m = hp.process(data, 100.0) Then we can visualise >>> plot_object = plotter(wd, m, show=False, title='some awesome title') This returns a plot object which can be visualized or saved or appended. See matplotlib API for more information on how to do this. A matplotlib plotting object is returned. This can be further processed and saved to a file. ''' #get color palette colorpalette = config.get_colorpalette_plotter() peaklist = working_data['peaklist'] ybeat = working_data['ybeat'] rejectedpeaks = working_data['removed_beats'] rejectedpeaks_y = working_data['removed_beats_y'] plt.title(title) plt.plot(working_data['hr'], color=colorpalette[0], label='heart rate signal', zorder=-10) if moving_average: plt.plot(working_data['rolling_mean'], color='gray', alpha=0.5) plt.scatter(peaklist, ybeat, color=colorpalette[1], label='BPM:%.2f' %(measures['bpm'])) plt.scatter(rejectedpeaks, rejectedpeaks_y, color=colorpalette[2], label='rejected peaks') #check if rejected segment detection is on and has rejected segments try: if len(working_data['rejected_segments']) >= 1: for segment in working_data['rejected_segments']: plt.axvspan(segment[0], segment[1], facecolor='red', alpha=0.5) except: pass plt.legend(loc=4, framealpha=0.6) if show: plt.show() else: return plt
[docs]def segment_plotter(working_data, measures, title='Heart Rate Signal Peak Detection', figsize=(6, 6), path='', start=0, end=None, step=1): # pragma: no cover '''plots analysis results Function that plots the results of segmentwise processing of heart rate signal and writes all results to separate files at the path provided. Parameters ---------- working_data : dict dictionary object that contains all heartpy's working data (temp) objects. will be created if not passed to function measures : dict dictionary object used by heartpy to store computed measures. Will be created if not passed to function title : str the title used in the plot figsize : tuple figsize tuple to be passed to matplotlib path : str the path where the files will be stored, folder must exist. start : int what segment to start plotting with default : 0 end : int last segment to plot. Must be smaller than total number of segments default : None, will plot until end step : int stepsize used when iterating over plots every step'th segment will be plotted default : 1 Returns ------- None Examples -------- This function has no examples. See documentation of heartpy for more info. ''' #sanity check assert 0 < step < len(working_data['hr']), 'step must be larger than zero and smaller than total number of segments' #set endpoint if not explicitly defined if end == None: end = len(working_data['hr']) else: #make sure it is defined within boundary conditions assert end <= len(working_data['hr']), 'defined "end" endpoint is larger than number of segments' #add trailing path slash if user omitted it if not (path.endswith('/') or path.endswith('\\')) and len(path) > 0: path += '/' #create path if it doesn't exist if not os.path.isdir(path): os.makedirs(path) #make plots filenum = 0 for i in range(start, end, step): wd_segment = {} m_segment = {} #assign values to sub-object for plotting purposes wd_segment['peaklist'] = working_data['peaklist'][i] wd_segment['ybeat'] = working_data['ybeat'][i] wd_segment['removed_beats'] = working_data['removed_beats'][i] wd_segment['removed_beats_y'] = working_data['removed_beats_y'][i] wd_segment['hr'] = working_data['hr'][i] wd_segment['rolling_mean'] = working_data['rolling_mean'][i] m_segment['bpm'] = measures['bpm'][i] try: wd_segment['rejected_segments'] = working_data['rejected_segments'][i] except: pass #plot it using built-in plotter plt.figure(figsize = figsize) p = plotter(wd_segment, m_segment, show=False) p.savefig('%s%i.png' %(path, filenum)) p.close() filenum += 1
[docs]def plot_poincare(working_data, measures, show = True, title='Poincare plot'): # pragma: no cover '''visualize poincare plot function that visualises poincare plot. Parameters ---------- working_data : dict dictionary object that contains all heartpy's working data (temp) objects. will be created if not passed to function measures : dict dictionary object used by heartpy to store computed measures. Will be created if not passed to function show : bool whether to show the plot right away, or return a matplotlib object for further manipulation title : str the title used in the plot Returns ------- out : matplotlib plot object only returned if show == False. Examples -------- This function has no examples. See documentation of heartpy for more info. ''' #get color palette colorpalette = config.get_colorpalette_poincare() #get values from dict x_plus = working_data['poincare']['x_plus'] x_minus = working_data['poincare']['x_minus'] sd1 = measures['sd1'] sd2 = measures['sd2'] #define figure fig, ax = plt.subplots(subplot_kw={'aspect': 'equal'}) #plot scatter plt.scatter(x_plus, x_minus, color = colorpalette[0], alpha = '0.75', label = 'peak-peak intervals') #plot identity line mins = np.min([x_plus, x_minus]) maxs = np.max([x_plus, x_minus]) identity_line = np.linspace(np.min(mins), np.max(maxs)) plt.plot(identity_line, identity_line, color='black', alpha=0.5, label = 'identity line') #rotate SD1, SD2 vectors 45 degrees counterclockwise sd1_xrot, sd1_yrot = rotate_vec(0, sd1, 45) sd2_xrot, sd2_yrot = rotate_vec(0, sd2, 45) #plot rotated SD1, SD2 lines plt.plot([np.mean(x_plus), np.mean(x_plus) + sd1_xrot], [np.mean(x_minus), np.mean(x_minus) + sd1_yrot], color = colorpalette[1], label = 'SD1') plt.plot([np.mean(x_plus), np.mean(x_plus) - sd2_xrot], [np.mean(x_minus), np.mean(x_minus) + sd2_yrot], color = colorpalette[2], label = 'SD2') #plot ellipse xmn = np.mean(x_plus) ymn = np.mean(x_minus) el = Ellipse((xmn, ymn), width = sd2 * 2, height = sd1 * 2, angle = 45.0) ax.add_artist(el) el.set_edgecolor((0,0,0)) el.fill = False plt.legend(loc=4, framealpha=0.6) plt.title(title) if show: plt.show() else: return plt
def rotate_vec(x, y, angle): '''rotates vector around origin point Function that takes vector and angle, and rotates around origin point with given amount of degrees. Helper function for poincare plotting Parameters ---------- x : int or float vector x coordinate y : int or float vector y coordinate angle: int or float the angle of rotation applied to the vecftor Returns ------- x_rot : float new x coordinate with rotation applied y_rot : float new x coordinate with rotation applied Examples -------- Given a vector (0,1), if we apply a rotation of 90 degrees clockwise we expect to get (1,0). Let's test >>> x_new, y_new = rotate_vec(0, 1, -90) >>> print('%.3f, %.3f' %(x_new, y_new)) 1.000, 0.000 ''' theta = np.radians(angle) cs = np.cos(theta) sn = np.sin(theta) x_rot = (x * cs) - (y * sn) y_rot = (x * sn) + (y * cs) return x_rot, y_rot
[docs]def plot_breathing(working_data, measures, show=True): # pragma: no cover '''plots extracted breathing signal and spectrogram Function that plots the breathing signal extracted from RR-intervals alongside its computed spectrogram representation. Parameters ---------- working_data : dict dictionary object that contains all heartpy's working data (temp) objects. will be created if not passed to function measures : dict dictionary object used by heartpy to store computed measures. Will be created if not passed to function show : bool whether to show the plot right away, or return a matplotlib object for further manipulation Returns ------- out : matplotlib plot object only returned if show == False. Examples -------- This function has no examples. See documentation of heartpy for more info. ''' plt.subplot(211) plt.plot(working_data['breathing_signal'], label='breathing signal') plt.xlabel('ms') plt.title('breathing signal extracted from RR-intervals') plt.subplot(212) plt.plot(working_data['breathing_frq'], working_data['breathing_psd'], label='spectrogram') plt.xlim(0, 2) plt.xlabel('Hz') plt.title('spectrogram extracted from breathing rate signal') plt.legend() plt.tight_layout() if show: plt.show() else: return plt