Analysis of neonatal ventilator alarms

Author: Dr Gusztav Belteki

This Notebook contains the code used for data processing, statistical analysis and visualization described in the following paper:

Belteki G, Morley CJ. Frequency, duration and cause of ventilator alarms on a neonatal intensive care unit. Arch Dis Child Fetal Neonatal Ed. 2018 Jul;103(4):F307-F311. doi: 10.1136/archdischild-2017-313493. Epub 2017 Oct 27. PubMed PMID: 29079651.

Link to the paper: https://fn.bmj.com/content/103/4/F307.long

Contact: gusztav.belteki@addenbrookes.nhs.uk; gbelteki@aol.com

Importing the required libraries and setting options


In [ ]:
import IPython
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import os
import sys
import pickle
import scipy as sp
from scipy import stats
from pandas import Series, DataFrame
from datetime import datetime, timedelta

%matplotlib inline

matplotlib.style.use('classic')
matplotlib.rcParams['figure.facecolor'] = 'w'

pd.set_option('display.max_rows', 100)
pd.set_option('display.max_columns', 100)
pd.set_option('mode.chained_assignment', None)

In [ ]:
print("Python version: {}".format(sys.version))
print("IPython version: {}".format(IPython.__version__))
print("pandas version: {}".format(pd.__version__))
print("matplotlib version: {}".format(matplotlib.__version__))
print("NumPy version: {}".format(np.__version__))
print("SciPy version: {}".format(sp.__version__))

Import modules containing own functions


In [ ]:
from gb_loader import *
from gb_stats import *
from gb_transform import *

List and set the working directory and the directories to write out data


In [ ]:
# Topic of the Notebook which will also be the name of the subfolder containing results
TOPIC = 'alarms_2'

# Name of the external hard drive
DRIVE = 'GUSZTI'

# Directory containing clinical and blood gas data
CWD = '/Users/guszti/ventilation_data'

# Directory on external drive to read the ventilation data from
DIR_READ = '/Volumes/%s/ventilation_data' % DRIVE

# Directory to write results and selected images to 
if not os.path.isdir('%s/%s/%s' % (CWD, 'Analyses', TOPIC)):
    os.makedirs('%s/%s/%s' % (CWD, 'Analyses', TOPIC))
DIR_WRITE = '%s/%s/%s' % (CWD, 'Analyses', TOPIC)

# Images and raw data will be written on an external hard drive
if not os.path.isdir('/Volumes/%s/data_dump/%s' % (DRIVE, TOPIC)):
    os.makedirs('/Volumes/%s/data_dump/%s' % (DRIVE, TOPIC))
DATA_DUMP = '/Volumes/%s/data_dump/%s' % (DRIVE, TOPIC)

In [ ]:
os.chdir(CWD)
os.getcwd()

In [ ]:
DIR_READ

In [ ]:
DIR_WRITE

In [ ]:
DATA_DUMP

List of the recordings


In [ ]:
# One recording from each patient, all of them 24 hours old or longer
# The sub folders containing the individual recordings have the same names within cwd

recordings = ['DG001', 'DG002_1', 'DG003', 'DG004', 'DG005_1', 'DG006_2',  'DG007', 'DG008', 'DG009', 'DG010',
              'DG011',  'DG013', 'DG014', 'DG015', 'DG016', 'DG017', 'DG018_1', 'DG020',
              'DG021', 'DG022', 'DG023',  'DG025', 'DG026', 'DG027', 'DG028', 'DG029', 'DG030',
              'DG031',  'DG032_2', 'DG033', 'DG034', 'DG035',  'DG037', 'DG038_1', 'DG039', 'DG040_1', 'DG041', 
              'DG042', 'DG043', 'DG044', 'DG045', 'DG046_2', 'DG047', 'DG048', 'DG049', 'DG050']

Import clinical details


In [ ]:
clinical_details = pd.read_excel('%s/data_grabber_patient_data_combined.xlsx' % CWD)
clinical_details.index = clinical_details['Recording']

In [ ]:
clinical_details.info()

In [ ]:
current_weights = {}
for recording in recordings:
    current_weights[recording] = clinical_details.loc[recording, 'Current weight' ] / 1000

Import ventilator parameters retrieved with 1/sec frequency


In [ ]:
slow_measurements = {}

for recording in recordings:
    flist = os.listdir('%s/%s' % (DIR_READ, recording))
    flist = [file for file in flist if not file.startswith('.')] # There are some hidden 
    # files on the hard drive starting with '.'; this step is necessary to ignore them
    files = slow_measurement_finder(flist)
    print('Loading recording %s' % recording)
    print(files)
    fnames = ['%s/%s/%s' % (DIR_READ, recording, filename) for filename in files]
    slow_measurements[recording] =  data_loader(fnames)

In [ ]:
# 46 recordings from 46 patients (4 recordings excluded as they were < 24 hours lon)
len(slow_measurements)

Calculating parameters / body weight kg


In [ ]:
for recording in recordings:
    try:
        a = slow_measurements[recording]
        a['VT_kg']       = a['5001|VT [mL]'] / current_weights[recording]
        a['VTi_kg']      = a['5001|VTi [mL]'] / current_weights[recording]
        a['VTe_kg']      = a['5001|VTe [mL]'] / current_weights[recording]
        a['VTmand_kg']   = a['5001|VTmand [mL]'] / current_weights[recording]
        a['VTspon_kg']   = a['5001|VTspon [mL]'] / current_weights[recording]
        a['VTimand_kg']  = a['5001|VTimand [mL]'] / current_weights[recording]
        a['VTemand_kg']  = a['5001|VTemand [mL]'] / current_weights[recording]
        a['VTispon_kg']  = a['5001|VTispon [mL]'] / current_weights[recording]
        a['VTespon_kg']  = a['5001|VTespon [mL]'] / current_weights[recording]
    except KeyError:
        # print('%s does not have all of the parameters' % recording)
        pass

In [ ]:
for recording in recordings:
    try:
        a = slow_measurements[recording]
        a['VThf_kg']      = a['5001|VThf [mL]'] / current_weights[recording]
        a['DCO2_corr_kg'] = a['5001|DCO2 [10*mL^2/s]'] * 10 / (current_weights[recording]) ** 2
    except KeyError:
        # print('%s does not have all of the parameters' % recording)
        pass

In [ ]:
for recording in recordings:
    try:
        a = slow_measurements[recording]
        a['MV_kg'] =      a['5001|MV [L/min]'] / current_weights[recording]
        a['MVi_kg'] =     a['5001|MVi [L/min]'] / current_weights[recording]
        a['MVe_kg'] =     a['5001|MVe [L/min]'] / current_weights[recording]
        a['MVemand_kg'] = a['5001|MVemand [L/min]'] / current_weights[recording]
        a['MVespon_kg'] = a['5001|MVespon [L/min]'] / current_weights[recording]
        a['MVleak_kg'] =  a['5001|MVleak [L/min]'] / current_weights[recording]
    except KeyError:
        # print('%s does not have all of the parameters' % recording)
        pass

Resampling to remove half-empty rows


In [ ]:
# 1/sec data are retrieved in two parts which need to be joined
# This resampling steps combines the two parts

for recording in recordings:
    slow_measurements[recording] = slow_measurements[recording].resample('1S').mean()

In [ ]:
# Example
slow_measurements['DG003'].head();

Save processed slow_measurements DataFrames to pickle archive


In [ ]:
len(recordings)

In [ ]:
rec1 = recordings[:15]; rec2 = recordings[15:30]; rec3 = recordings[30:40]; rec4 = recordings[40:]
slow_measurements_1 = { key: value for key, value in slow_measurements.items() if key in rec1} with open('%s/%s.pickle' % (DATA_DUMP, 'slow_measurements_1'), 'wb') as handle: pickle.dump(slow_measurements_1, handle, protocol=pickle.HIGHEST_PROTOCOL)
slow_measurements_2 = { key: value for key, value in slow_measurements.items() if key in rec2} with open('%s/%s.pickle' % (DATA_DUMP, 'slow_measurements_2'), 'wb') as handle: pickle.dump(slow_measurements_2, handle, protocol=pickle.HIGHEST_PROTOCOL)
slow_measurements_3 = { key: value for key, value in slow_measurements.items() if key in rec3} with open('%s/%s.pickle' % (DATA_DUMP, 'slow_measurements_3'), 'wb') as handle: pickle.dump(slow_measurements_3, handle, protocol=pickle.HIGHEST_PROTOCOL)
slow_measurements_4 = { key: value for key, value in slow_measurements.items() if key in rec3} with open('%s/%s.pickle' % (DATA_DUMP, 'slow_measurements_4'), 'wb') as handle: pickle.dump(slow_measurements_4, handle, protocol=pickle.HIGHEST_PROTOCOL)

Import processed 'slow_measurements' data from pickle archive

with open('%s/%s.pickle' % (DATA_DUMP, 'slow_measurements_1'), 'rb') as handle: slow_measurements_1 = pickle.load(handle) with open('%s/%s.pickle' % (DATA_DUMP, 'slow_measurements_2'), 'rb') as handle: slow_measurements_2 = pickle.load(handle) with open('%s/%s.pickle' % (DATA_DUMP, 'slow_measurements_3'), 'rb') as handle: slow_measurements_3 = pickle.load(handle) with open('%s/%s.pickle' % (DATA_DUMP, 'slow_measurements_4'), 'rb') as handle: slow_measurements_4 = pickle.load(handle)
slow_measurements = {} slow_measurements.update(slow_measurements_1) slow_measurements.update(slow_measurements_2) slow_measurements.update(slow_measurements_3) slow_measurements.update(slow_measurements_4)
del slow_measurements_1, slow_measurements_2, slow_measurements_3, slow_measurements_4

Calculate recording durations


In [ ]:
# Time stamps are obtained from 'slow measurements' 

recording_duration = {}
for recording in recordings:
    recording_duration[recording] = slow_measurements[recording].index[-1] - slow_measurements[recording].index[0]

In [ ]:
recording_duration_seconds = {}
recording_duration_hours = {}

for recording in recordings:
    temp = recording_duration[recording]
    recording_duration_seconds[recording] = temp.total_seconds()
    recording_duration_hours[recording] = temp.total_seconds() / 3600

Visualising recording durations


In [ ]:
v = list(range(1, len(recordings)+1))
w = [value for key, value in sorted(recording_duration_hours.items()) if key in recordings]

In [ ]:
fig = plt.figure()
fig.set_size_inches(20, 10)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)
ax1 = fig.add_subplot(1, 1, 1);
ax1.bar(v, w, color = 'blue')
plt.xlabel("Recordings", fontsize  = 22)
plt.ylabel("Hours", fontsize  = 22)
plt.title("Recording periods" , fontsize = 22)
plt.yticks(fontsize = 22)
plt.xticks([i+1.5  for i, _ in enumerate(recordings)], recordings, fontsize = 22, rotation = 'vertical');
plt.grid()

fig.savefig('%s/%s' % (DIR_WRITE, 'recording_durations.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

Write recording times out into files


In [ ]:
recording_times_frame = DataFrame([recording_duration, recording_duration_hours, recording_duration_seconds],
                            index = ['days', 'hours', 'seconds'])

In [ ]:
recording_times_frame

In [ ]:
writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'recording_periods.xlsx'))
recording_times_frame.to_excel(writer,'rec_periods')
writer.save()

Import ventilator modes and settings

Import ventilation settings

In [ ]:
vent_settings = {}

for recording in recordings:
    flist = os.listdir('%s/%s' % (DIR_READ, recording))
    flist = [file for file in flist if not file.startswith('.')] # There are some hidden 
    # files on the hard drive starting with '.'; this step is necessary to ignore them
    files = slow_setting_finder(flist)
    # print('Loading recording %s' % recording)
    # print(files)
    fnames = ['%s/%s/%s' % (DIR_READ, recording, filename) for filename in files]
    vent_settings[recording] =  data_loader(fnames)

In [ ]:
# remove less important ventilator settings to simplify the table

vent_settings_selected = {}
for recording in recordings:
    vent_settings_selected[recording] = vent_settings_cleaner(vent_settings[recording])

In [ ]:
# Create a another dictionary of Dataframes wit some of the ventilation settings (set VT, set RR, set Pmax)

lsts = [(['VT_weight'], ['VTi', 'VThf']), (['RR_set'], ['RR']), (['Pmax'], ['Pmax', 'Ampl hf max'])]
vent_settings_2 = {}
                                                            
for recording in recordings:
    frmes = []                                                       
    for name, pars in lsts:
        if pars in [['VTi', 'VThf']]:
            ind = []
            val = []
            for index, row in vent_settings_selected[recording].iterrows():
                if row['Id'] in pars:
                    ind.append(index)
                    val.append(row['Value New'] / current_weights[recording])
                frmes.append(DataFrame(val, index = ind, columns = name))
        else:
            ind = []
            val = []
            for index, row in vent_settings_selected[recording].iterrows():
                if row['Id'] in pars:
                    ind.append(index)
                    val.append(row['Value New'])
                frmes.append(DataFrame(val, index = ind, columns = name))
    vent_settings_2[recording] = pd.concat(frmes)
    vent_settings_2[recording].drop_duplicates(inplace = True)
Import ventilation modes

In [ ]:
vent_modes = {}

for recording in recordings:
    flist = os.listdir('%s/%s' % (DIR_READ, recording))
    flist = [file for file in flist if not file.startswith('.')] # There are some hidden 
    # files on the hard drive starting with '.'; this step is necessary to ignore them
    files = slow_text_finder(flist)
    # print('Loading recording %s' % recording)
    # print(files)
    fnames = ['%s/%s/%s' % (DIR_READ, recording, filename) for filename in files]
    vent_modes[recording] =  data_loader(fnames)

In [ ]:
# remove less important ventilator mode settings to simplify the table

vent_modes_selected = {}
for recording in recordings:
    vent_modes_selected[recording] = vent_mode_cleaner(vent_modes[recording])

Save ventilation modes and settings into Excel files


In [ ]:
writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'ventilator_settings.xlsx'))
for recording in recordings:
    vent_settings[recording].to_excel(writer,'%s' % recording)
writer.save()

In [ ]:
writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'ventilator_settings_selected.xlsx'))
for recording in recordings:
    vent_settings_selected[recording].to_excel(writer,'%s' % recording)
writer.save()

In [ ]:
writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'ventilator_settings_2.xlsx'))
for recording in recordings:
    vent_settings_2[recording].to_excel(writer,'%s' % recording)
writer.save()

In [ ]:
writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'ventilator_modes.xlsx'))
for recording in recordings:
    vent_modes[recording].to_excel(writer,'%s' % recording)
writer.save()

In [ ]:
writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'ventilator_modes_selected.xlsx'))
for recording in recordings:
    vent_modes_selected[recording].to_excel(writer,'%s' % recording)
writer.save()

Import alarm settings


In [ ]:
alarm_settings = {}

for recording in recordings:
    flist = os.listdir('%s/%s' % (DIR_READ, recording))
    flist = [file for file in flist if not file.startswith('.')] # There are some hidden 
    # files on the hard drive starting with '.'; this step is necessary to ignore them
    files = alarm_setting_finder(flist)
    # print('Loading recording %s' % recording)
    # print(files)
    fnames = ['%s/%s/%s' % (DIR_READ, recording, filename) for filename in files]
    alarm_settings[recording] =  data_loader(fnames)

In [ ]:
# Remove etCO2 limits which were not used

alarm_settings_selected = {}

for recording in recordings:
    alarm_settings_selected[recording] = alarm_setting_cleaner(alarm_settings[recording])

In [ ]:
# Create a another dictionary of Dataframes with some of the alarm settings 

lsts = [(['MV_high_weight'], ['MVe_HL']), (['MV_low_weight'], ['MVe_LL']), 
        (['PIP_high'], ['PIP_HL']), (['RR_high'], ['RR_HL'])]
alarm_settings_2 = {}
                                                            
for recording in recordings:
    frmes = []                                                       
    for name, pars in lsts:
        if pars in [['MVe_HL'], ['MVe_LL']]:
            ind = []
            val = []
            for index, row in alarm_settings_selected[recording].iterrows():
                if row['Id'] in pars:
                    ind.append(index)
                    val.append(row['Value New'] / current_weights[recording])
                frmes.append(DataFrame(val, index = ind, columns = name))
        else:
            ind = []
            val = []
            for index, row in alarm_settings_selected[recording].iterrows():
                if row['Id'] in pars:
                    ind.append(index)
                    val.append(row['Value New'])
                frmes.append(DataFrame(val, index = ind, columns = name))
    alarm_settings_2[recording] = pd.concat(frmes)
    alarm_settings_2[recording].drop_duplicates(inplace = True)

In [ ]:
# Write DataFrames containing alarm settings to a multisheet Excel file

writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'alarm_settings.xlsx'))
for recording in recordings:
    alarm_settings[recording].to_excel(writer,'%s' % recording)
writer.save()

In [ ]:
# Write DataFrames containing alarm settings to a multisheet Excel file

writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'alarm_settings_2.xlsx'))
for recording in recordings:
    alarm_settings_2[recording].to_excel(writer,'%s' % recording)
writer.save()

Import alarm states


In [ ]:
alarm_states = {}

for recording in recordings:
    flist = os.listdir('%s/%s' % (DIR_READ, recording))
    flist = [file for file in flist if not file.startswith('.')] # There are some hidden 
    # files on the hard drive starting with '.'; this step is necessary to ignore them
    files = alarm_state_finder(flist)
    # print('Loading recording %s' % recording)
    # print(files)
    fnames = ['%s/%s/%s' % (DIR_READ, recording, filename) for filename in files]
    alarm_states[recording] =  data_loader(fnames)

In [ ]:
# Write DataFrames containing alarm states to a multisheet Excel file

writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'alarm_states.xlsx'))
for recording in recordings:
    alarm_states[recording].to_excel(writer,'%s' % recording)
writer.save()

Calculate the total and average time of all recordings


In [ ]:
total_recording_time = timedelta(0)
for recording in recordings:
    total_recording_time += recording_duration[recording]

In [ ]:
total_recording_time

In [ ]:
mean_recording_time = total_recording_time / len(recordings)
mean_recording_time

Generate alarm events from alarm states


In [ ]:
# Define function to retrieve alarm events from alarm timing data
def alarm_events_calculator(dframe, al):
    
    '''
    DataFrame, str -> DataFrame
    
    dframe: DataFrame containing alarm states
    al:  alarm category (string)
    
    Returns a pd.DataFrame object with the time stamps when the alarm went off and the duration (in seconds)
    of the alarm for alarm 'al' in recording 'rec'
    '''
    
    alarms = dframe
    alarm = alarms[alarms.Name == al]
    length = len(alarm)
    delta = np.array([(alarm.Date_Time[i] - alarm.Date_Time[i-1]).total_seconds() 
            for i in range(1, length) if alarm['State New'][i] == 'NotActive' and alarm['State New'][i-1] == 'Active'])
    stamp = np.array([alarm.index[i-1] 
            for i in range(1, length) if alarm['State New'][i] == 'NotActive' and alarm['State New'][i-1] == 'Active'])
    data = {'duration_seconds': delta, 'time_went_off': stamp,}
    alarm_t = DataFrame(data, columns = ['time_went_off', 'duration_seconds'])
    return alarm_t

Using the files containing the alarm states, for each alarm category in each recording create a DataFrame with the timestamps the alarm went off and the duration of the alarm and store them in a dictionary of dictionaries


In [ ]:
# Create a list of alarms occurring during each recording

alarm_list = {}

for recording in recordings:
    alarm_list[recording] = sorted(set(alarm_states[recording].Name))

In [ ]:
alarm_events = {}

for recording in recordings:
    alarm_events[recording] = {}
    for alarm in alarm_list[recording]:
        alarm_events[recording][alarm] = alarm_events_calculator(alarm_states[recording], alarm)

In [ ]:
# Write Dataframes containing the alarm events in Excel files,
# one Excel file for each recording

for recording in recordings:
    writer = pd.ExcelWriter('%s/%s%s' % (DIR_WRITE, recording, '_alarm_events.xlsx'))
    for alarm in alarm_list[recording]:
        alarm_events[recording][alarm].to_excel(writer, alarm[:20])
    
    writer.save()

Calculate descriptive statistics for each alarm in each recording and write them to file


In [ ]:
def alarm_stats_calculator(dframe, rec, al):
    '''
    dframe: DataFrame containing alarm events 
    rec: recording (string)
    al: alarm (string)
    
    Returns detailed statistics about a particular alarm (al) in a particular recording (rec);
    - number of times alarm went off and its value normalized to 24 hour periods
    - mean, median, standard deviation, mean absolute deviation, minimum, 25th centile, 75th centile, maximum
    time period when the alarm was off
    - the total amount of time the alarm was off and its relative value in percent as the total recording time 
    '''
    alarm = dframe[al].duration_seconds
    return  (alarm.size, round((alarm.size / (recording_duration_hours[rec] / 24)), 1), 
            round(alarm.mean() , 1), round(alarm.median(), 1), round(alarm.std(), 1), round(alarm.min() , 1), 
            round(alarm.quantile(0.25), 1), round(alarm.quantile(0.75), 1), round(alarm.max(), 1),
            round(alarm.sum(), 1), round(alarm.sum() * 100 / recording_duration_seconds[rec] ,3))

In [ ]:
alarm_stats = {}

for recording in recordings:
    alarm_stats[recording] = {}
    for alarm in alarm_list[recording]:
        data = alarm_stats_calculator(alarm_events[recording], recording, alarm)
        frame = DataFrame([data], columns = ['number of events', 'number of event per 24h', 
                                             'mean duration (s)', 'median duration (s)', 'SD duration (s)', 
                                             'miminum duration (s)', 
                                             'duration 25th centile (s)', 'duration 75th centile (s)', 
                                             'maximum duration (s)', 'cumulative duration (s)', 
                                             'percentage of recording length (%)'], index = [alarm])
        alarm_stats[recording][alarm] = frame

In [ ]:
# Write descriptive statistics in a multisheet Excel file

writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'alarm_stats.xlsx'))
for recording in recordings:
    stats = []
    for alarm in alarm_stats[recording]:
        stats.append(alarm_stats[recording][alarm])
    stats_all = pd.concat(stats)
    stats_all.to_excel(writer, recording)
writer.save()

Visualise alarm statistics for the individual alarms in the individual recording


In [ ]:
# Generates a plot with the cumulative times (in seconds) of the various alarm occurring during recording (rec).
# Displays the plot

def alarm_plot_1(rec):
    fig = plt.figure()
    fig.set_size_inches(25, 8)
    fig.subplots_adjust(left=0.4, bottom=None, right=None, top=None,
    wspace=None, hspace=0.7)
    ax1 = fig.add_subplot(1, 1, 1)
    xs = [i + 0.1 for i, _ in enumerate(alarm_list[rec])]
    stats = []
    for alarm in alarm_list[rec]:
        stats.append(alarm_stats[rec][alarm]['cumulative duration (s)'])
    stats_all = pd.concat(stats)
    plt.barh(xs, stats_all, color = 'red')
    plt.xlabel("seconds", fontsize  = 24)
    plt.title("Recording %s : How long was the alarm active over the %d seconds of recording?" % (rec, 
                recording_duration_seconds[rec]), fontsize = 22)
    plt.yticks([i + 0.5 for i, _ in enumerate(alarm_list[rec])], alarm_list[rec], fontsize = 22)
    plt.xticks(fontsize = 20)

In [ ]:
# Generates a plot with the cumulative times (in seconds) of the various alarm occurring during recording (rec).
# Does not displays the plot but write it into a jpg file.
# NB: the resolution of the image is only 100 dpi - for publication quality higher is needed

def alarm_plot_1_write(rec):
    fig = plt.figure()
    fig.set_size_inches(25, 8)
    fig.subplots_adjust(left=0.4, bottom=None, right=None, top=None,
    wspace=None, hspace=0.7)
    ax1 = fig.add_subplot(1, 1, 1)
    xs = [i + 0.1 for i, _ in enumerate(alarm_list[rec])]
    stats = []
    for alarm in alarm_list[rec]:
        stats.append(alarm_stats[rec][alarm]['cumulative duration (s)'])
    stats_all = pd.concat(stats)
    plt.barh(xs, stats_all, color = 'red')
    plt.xlabel("seconds", fontsize  = 24)
    plt.title("Recording %s : How long was the alarm active over the %d seconds of recording?" % (rec, 
                recording_duration_seconds[rec]), fontsize = 22)
    plt.yticks([i + 0.5 for i, _ in enumerate(alarm_list[rec])], alarm_list[rec], fontsize = 22)
    plt.xticks(fontsize = 20)
    
    fig.savefig('%s/%s_%s.jpg' % (dir_write, 'alarm_durations_1', rec), dpi=100, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)
    plt.close(fig)

In [ ]:
# Generates a plot with the cumulative times (expressed as percentage of the total recording time) 
# of the various alarm occurring during recording (rec).
# Displays the plot

def alarm_plot_2(rec):
    fig = plt.figure()
    fig.set_size_inches(25, 8)
    fig.subplots_adjust(left=0.4, bottom=None, right=None, top=None,
    wspace=None, hspace=0.7)
    ax1 = fig.add_subplot(1, 1, 1)
    xs = [i + 0.1 for i, _ in enumerate(alarm_list[rec])]
    stats = []
    for alarm in alarm_list[rec]:
        stats.append(alarm_stats[rec][alarm]['percentage of recording length (%)'])
    stats_all = pd.concat(stats)
    plt.barh(xs, stats_all, color = 'red')
    plt.xlabel("% of total recording time", fontsize  = 24)
    plt.title("Recording %s: How long the alarm active over the %s hours of recording?" % (rec, 
            str(recording_duration[rec])), fontsize = 22)
    plt.yticks([i + 0.5 for i, _ in enumerate(alarm_list[rec])], alarm_list[rec], fontsize = 22)
    plt.xticks(fontsize = 20)

In [ ]:
# Generates a plot with the cumulative times (expressed as percentage of the total recording time) 
# of the various alarm occurring during recording (rec).
# Does not displays the plot but write it into a jpg file.
# NB: the resolution of the image is only 100 dpi - for publication quality higher is needed

def alarm_plot_2_write(rec):
    fig = plt.figure()
    fig.set_size_inches(25, 8)
    fig.subplots_adjust(left=0.4, bottom=None, right=None, top=None,
    wspace=None, hspace=0.7)
    ax1 = fig.add_subplot(1, 1, 1)
    xs = [i + 0.1 for i, _ in enumerate(alarm_list[rec])]
    stats = []
    for alarm in alarm_list[rec]:
        stats.append(alarm_stats[rec][alarm]['percentage of recording length (%)'])
    stats_all = pd.concat(stats)
    plt.barh(xs, stats_all, color = 'red')
    plt.xlabel("% of total recording time", fontsize  = 24)
    plt.title("Recording %s: How long the alarm active over the %s hours of recording?" % (rec, 
            str(recording_duration[rec])), fontsize = 22)
    plt.yticks([i + 0.5 for i, _ in enumerate(alarm_list[rec])], alarm_list[rec], fontsize = 22)
    plt.xticks(fontsize = 20)
    
    fig.savefig('%s/%s_%s.jpg' % (dir_write, 'alarm_durations_2', rec), dpi=100, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)
    plt.close(fig)

In [ ]:
# Displays the individual alarm events of the recording (rec) along the time axis
# Displays the plot

def alarm_plot_3(rec):
    alarm_state = alarm_states[rec]
    numbered = Series(np.zeros(len(alarm_state)), index = alarm_state.index)
    for i in range(1, len(alarm_state)):
        if alarm_state.iloc[i]['State New'] == 'Active':
            numbered[i] = alarm_list[rec].index(alarm_state.iloc[i]['Id']) + 1
    
    fig = plt.figure()
    fig.set_size_inches(17, 8)
    fig.subplots_adjust(left=0.4, bottom=None, right=None, top=None,
    wspace=None, hspace=0.7)
    ax1 = fig.add_subplot(1, 1, 1);

    ax1.plot(alarm_state.index,  numbered, '|', color = 'red', markersize = 16, markeredgewidth = 1 )
    plt.xlabel("Time", fontsize  = 20)
    plt.title("Alarm events during recording %s" % rec , fontsize = 24)
    plt.yticks([i+1  for i, _ in enumerate(alarm_list[rec])], alarm_list[rec], fontsize = 18);
    plt.xticks(fontsize = 14, rotation = 30)
    plt.ylim(0.5, len(alarm_list[rec]) + 0.5);

In [ ]:
# Displays the individual alarm events of recording (rec) along the time axis
# Does not displays the plot but write it into a jpg file.
# NB: the resolution of the image is only 100 dpi - for publication quality higher is needed

def alarm_plot_3_write(rec):
    alarm_state = alarm_states[rec]
    numbered = Series(np.zeros(len(alarm_state)), index = alarm_state.index)
    for i in range(1, len(alarm_state)):
        if alarm_state.iloc[i]['State New'] == 'Active':
            numbered[i] = alarm_list[rec].index(alarm_state.iloc[i]['Id']) + 1
    
    fig = plt.figure()
    fig.set_size_inches(17, 8)
    fig.subplots_adjust(left=0.4, bottom=None, right=None, top=None,
    wspace=None, hspace=0.7)
    ax1 = fig.add_subplot(1, 1, 1);

    ax1.plot(alarm_state.index,  numbered, '|', color = 'red', markersize = 16, markeredgewidth = 1 )
    plt.xlabel("Time", fontsize  = 20)
    plt.title("Alarm events during recording %s" % rec , fontsize = 24)
    plt.yticks([i+1  for i, _ in enumerate(alarm_list[rec])], alarm_list[rec], fontsize = 18);
    plt.xticks(fontsize = 14, rotation = 30)
    plt.ylim(0.5, len(alarm_list[rec]) + 0.5)
    
    fig.savefig('%s/%s_%s.pdf' % (dir_write, 'individual_alarms', rec), dpi=100, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='pdf',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)
    plt.close(fig)
Example plots

In [ ]:
alarm_plot_1('DG032_2')

In [ ]:
alarm_plot_2('DG032_2')

In [ ]:
alarm_plot_3('DG032_2')

Write all graphs to files

for recording in recordings: alarm_plot_1_write(recording) alarm_plot_2_write(recording) alarm_plot_3_write(recording)

Generate cumulative descriptive statistics of all alarms combined in each recording

For each recording, what was the total number of alarm events and the number of events normalized for 24 hour periods


In [ ]:
total_alarm_number_recordings = {} # dictionary containing the total number of alarm events in each recording
for recording in recordings:
    total = 0
    for alarm in alarm_list[recording]:
        total += len(alarm_events[recording][alarm].index)
    total_alarm_number_recordings[recording] = total

In [ ]:
total_alarm_number_recordings_24H = {} # dictionary containing the total number of alarm events in each recording
                                       # corrected for 24 hour period
for recording in recordings:
    total_alarm_number_recordings_24H[recording] = (total_alarm_number_recordings[recording] / 
                                                    (recording_duration[recording].total_seconds() / 86400))

In each recording, what was the mean, median, sd, mad, min, 25pc, 75pc, max of alarm durations


In [ ]:
alarm_durations_recordings = {} # a dictionary of Series. Each series contains all the alarm durations of a recording
for recording in recordings:
    durations = []
    for alarm in alarm_list[recording]:
        durations.append(alarm_events[recording][alarm]['duration_seconds'])
    durations = pd.concat(durations)
    alarm_durations_recordings[recording] = durations

In [ ]:
# Dictionaries containing various descriptive statistics for each recording

mean_alarm_duration_recordings = {}
median_alarm_duration_recordings = {}
sd_alarm_duration_recordings = {}
mad_alarm_duration_recordings = {}
min_alarm_duration_recordings = {}
pc25_alarm_duration_recordings = {}
pc75_alarm_duration_recordings = {}
max_alarm_duration_recordings = {}

In [ ]:
for recording in recordings:
    mean_alarm_duration_recordings[recording] = round(alarm_durations_recordings[recording].mean(), 4)
    median_alarm_duration_recordings[recording] = round(alarm_durations_recordings[recording].median(), 4)
    sd_alarm_duration_recordings[recording] = round(alarm_durations_recordings[recording].std(), 4)
    mad_alarm_duration_recordings[recording] = round(alarm_durations_recordings[recording].mad(), 4)
    min_alarm_duration_recordings[recording] = round(alarm_durations_recordings[recording].min(), 4)
    pc25_alarm_duration_recordings[recording] = round(alarm_durations_recordings[recording].quantile(0.25), 4)
    pc75_alarm_duration_recordings[recording] = round(alarm_durations_recordings[recording].quantile(0.75), 4)
    max_alarm_duration_recordings[recording] = round(alarm_durations_recordings[recording].max(), 4)

In [ ]:
# Create DataFrame containing cumulative alarm statistics for each recording

alarm_stats_cum_rec = DataFrame([total_alarm_number_recordings, 
                                 total_alarm_number_recordings_24H,
                                 mean_alarm_duration_recordings,  
                                 median_alarm_duration_recordings,
                                 sd_alarm_duration_recordings,
                                 mad_alarm_duration_recordings,
                                 min_alarm_duration_recordings,
                                 pc25_alarm_duration_recordings,
                                 pc75_alarm_duration_recordings,
                                 max_alarm_duration_recordings],
    index = ['count', 'count per 24h', 'mean duration (sec)', 'median duration (sec)', 'sd duration (sec)', 
             'mad duration (sec)', 'min duration (sec)', '25th cent duration (sec)', '75th cent duration (sec)',
             'max duration (sec)'])

In [ ]:
alarm_stats_cum_rec.round(2)

In [ ]:
# Write statistics to Excel file

writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'alarm_stats_cum_rec.xlsx'))
alarm_stats_cum_rec.round(2).to_excel(writer, 'cumulative_stats')
writer.save()

Visualize cumulative statistics of recordings


In [ ]:
# Plot the absolute number of alarm events for each recording

fig = plt.figure()
fig.set_size_inches(12, 12)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1);
ax1.barh(list(range(1, len(recordings)+1)), alarm_stats_cum_rec.loc['count', :], color = 'blue')
plt.ylabel("Recordings", fontsize  = 22)
plt.xlabel("", fontsize  = 22)
plt.title("Number of alarm events" , fontsize = 26)
ax1.tick_params(which = 'both', labelsize=14)
plt.yticks([i+1.5  for i, _ in enumerate(recordings)], recordings, rotation = 'horizontal')
plt.grid()

fig.savefig('%s/%s' % (DIR_WRITE, 'number_events_rec.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

In [ ]:
# Plot the number of alarm events in each recording normalised for 24 hour periods
fig = plt.figure()
fig.set_size_inches(12, 12)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1);
ax1.barh(list(range(1, len(recordings)+1)), alarm_stats_cum_rec.loc['count per 24h', :], color = 'blue')
plt.ylabel("Recordings", fontsize  = 22)
plt.xlabel("", fontsize  = 22)
plt.title("Number of alarm events per 24 hours" , fontsize = 26)
ax1.tick_params(which = 'both', labelsize=14)
plt.yticks([i+1.5  for i, _ in enumerate(recordings)], recordings, rotation = 'horizontal')
plt.grid()

fig.savefig('%s/%s' % (DIR_WRITE, 'number_events_24H_rec.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

In [ ]:
# Median duration of alarm events

fig = plt.figure()
fig.set_size_inches(12, 12)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1);
ax1.barh(list(range(1, len(recordings)+1)), alarm_stats_cum_rec.loc['mean duration (sec)', :], color = 'blue')
plt.ylabel("Recordings", fontsize  = 22)
plt.xlabel("seconds", fontsize  = 22)
plt.title("Median duration of alarm events" , fontsize = 26)
ax1.tick_params(which = 'both', labelsize=14)
plt.yticks([i+1.5  for i, _ in enumerate(recordings)], recordings,  rotation = 'horizontal')
plt.grid()

fig.savefig('%s/%s' % (DIR_WRITE, 'median_duration_rec.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

Generate cumulative statistics of each alarm in all recordings combined


In [ ]:
# Create a list of all alarms occurring in any recording

total_alarm_list = set()
for recording in recordings:
    total_alarm_list.update(alarm_list[recording])
total_alarm_list = sorted(total_alarm_list)

In [ ]:
# A list of all alarms occurring during the service evaluation

total_alarm_list

In [ ]:
# Write alarm list to Excel file

writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'total_alarm_list.xlsx'))
DataFrame(total_alarm_list, columns = ['alarm categories']).to_excel(writer, 'total_alarm_list')
writer.save()

For each alarm, what was number of alarm events across all recordings and the number of events normalized per 24 hour recording time


In [ ]:
total_alarm_number_alarms = {} # dictionary containing the number of alarm events in all recordings for the 
                               # various alarm categories
for alarm in total_alarm_list:
    total = 0
    for recording in recordings:
        if alarm in alarm_list[recording]:
            total += len(alarm_events[recording][alarm].index)
    total_alarm_number_alarms[alarm] = total

In [ ]:
# Write alarm list to Excel file

writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'total_alarm_list_numbers.xlsx'))
DataFrame([total_alarm_number_alarms]).T.to_excel(writer, 'total_alarm_list')
writer.save()

In [ ]:
total_alarm_number_alarms_24H = {} # dictionary containing the number of alarm events in all recordings for the 
                                   # various alarm categories normalized for 24 hour recording periods
for alarm in total_alarm_list:
    total_alarm_number_alarms_24H[alarm] = round(((total_alarm_number_alarms[alarm] / 
                                                    (total_recording_time.total_seconds() / 86400))), 4)

For each alarm, what was the total duration of alarm events across all recordings and normalized per 24 hour recording time


In [ ]:
alarm_durations_alarms = {} # a dictionary of Series. Each Series contains all durations of a particular alarm
                            # in all recordings

for alarm in total_alarm_list:
    durations = []
    for recording in recordings:
        if alarm in alarm_list[recording]:
            durations.append(alarm_events[recording][alarm]['duration_seconds'])
    durations = pd.concat(durations)
    alarm_durations_alarms[alarm] = durations

In [ ]:
cum_alarm_duration_alarms = {} # dictionary containing the total duration of alarms in all recordings for the 
                               # various alarm categories 

for alarm in total_alarm_list:
    cum_alarm_duration_alarms[alarm] = round(alarm_durations_alarms[alarm].sum(), 4)

In [ ]:
cum_alarm_duration_alarms_24H = {} # dictionary containing the total duration of alarms in all recordings for the 
                                   # various alarm categories normalized for 24 hour recording periods
for alarm in total_alarm_list:
    cum_alarm_duration_alarms_24H[alarm] = round(((cum_alarm_duration_alarms[alarm] / 
                                                    (total_recording_time.total_seconds() / 86400))), 4)

For each alarm what was the mean, median, sd, mad, min, 25pc, 75pc, max of alarm durations


In [ ]:
# libraries containing various descriptive statistics for each recording

mean_alarm_duration_alarms = {}
median_alarm_duration_alarms = {}
sd_alarm_duration_alarms = {}
mad_alarm_duration_alarms = {}
min_alarm_duration_alarms = {}
pc25_alarm_duration_alarms = {}
pc75_alarm_duration_alarms = {}
max_alarm_duration_alarms = {}

In [ ]:
for alarm in total_alarm_list:
    mean_alarm_duration_alarms[alarm] = round(alarm_durations_alarms[alarm].mean(), 4)
    median_alarm_duration_alarms[alarm] = round(alarm_durations_alarms[alarm].median(), 4)
    sd_alarm_duration_alarms[alarm] = round(alarm_durations_alarms[alarm].std(), 4)
    mad_alarm_duration_alarms[alarm] = round(alarm_durations_alarms[alarm].mad(), 4)
    min_alarm_duration_alarms[alarm] = round(alarm_durations_alarms[alarm].min(), 4)
    pc25_alarm_duration_alarms[alarm] = round(alarm_durations_alarms[alarm].quantile(0.25), 4)
    pc75_alarm_duration_alarms[alarm] = round(alarm_durations_alarms[alarm].quantile(0.75), 4)
    max_alarm_duration_alarms[alarm] = round(alarm_durations_alarms[alarm].max(), 4)

In [ ]:
# Create DataFrame containing cumulative alarm statistics for each alarm

alarm_stats_cum_al = DataFrame([total_alarm_number_alarms, 
                                 total_alarm_number_alarms_24H,
                                 cum_alarm_duration_alarms,
                                 cum_alarm_duration_alarms_24H,
                                 mean_alarm_duration_alarms,  
                                 median_alarm_duration_alarms,
                                 sd_alarm_duration_alarms,
                                 mad_alarm_duration_alarms,
                                 min_alarm_duration_alarms,
                                 pc25_alarm_duration_alarms,
                                 pc75_alarm_duration_alarms,
                                 max_alarm_duration_alarms],
    index = ['count', 'count per 24h', 'total alarm duration (sec)', 'total alarm duration per 24 hours (sec)', 
             'mean duration (sec)', 'median duration (sec)', 'sd duration (sec)', 'mad duration (sec)', 
             'min duration (sec)', '25th cent duration (sec)', '75th cent duration (sec)',
             'max duration (sec)'])

In [ ]:
# Dataframe containing cumulative alarm statistics for each alarm

alarm_stats_cum_al.round(2)

In [ ]:
# Write Dataframe containing cumulative alarm statistics for each alarm to Excel file

writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'alarm_stats_cum_al.xlsx'))
alarm_stats_cum_al.round(2).to_excel(writer, 'cumulative_stats')
writer.save()

Visualising cumulative statistics of alarms


In [ ]:
# Reduce a too long alarm name
total_alarm_list[0] = 'A setting, alarm limit or vent...'

In [ ]:
# Total number of alarm events in all recordings

fig = plt.figure()
fig.set_size_inches(17, 12)
fig.subplots_adjust(left=0.4, bottom=None, right=None, top=None, wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1);
ax1.barh(list(range(1, len(total_alarm_list)+1)), alarm_stats_cum_al.loc['count', :], color = 'blue')
plt.ylabel("Alarms", fontsize  = 22)
plt.xlabel("", fontsize  = 22)
plt.title("Number of alarm events" , fontsize = 26)
ax1.tick_params(which = 'both', labelsize=14)
ax1.tick_params(which = 'both', labelsize=14)
plt.yticks([i+1.5  for i, _ in enumerate(total_alarm_list)], total_alarm_list, rotation = 'horizontal')
plt.grid()

fig.savefig('%s/%s' % (DIR_WRITE, 'number_events_al.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

In [ ]:
# Total number of alarm events in all recordings normalized for 24 hour periods

fig = plt.figure()
fig.set_size_inches(17, 12)
fig.subplots_adjust(left=0.4, bottom=None, right=None, top=None, wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1);
ax1.barh(list(range(1, len(total_alarm_list)+1)), alarm_stats_cum_al.loc['count per 24h', :], color = 'blue')
plt.ylabel("Alarms", fontsize  = 22)
plt.xlabel("", fontsize  = 22)
plt.title("Number of alarm events per 24 hour" , fontsize = 26)
ax1.tick_params(which = 'both', labelsize=14)
plt.yticks([i+1.5  for i, _ in enumerate(total_alarm_list)], total_alarm_list, rotation = 'horizontal')
plt.grid()

fig.savefig('%s/%s' % (DIR_WRITE, 'number_events_24H_al.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

In [ ]:
# Median duration of alarm events in all recordings

fig = plt.figure()
fig.set_size_inches(17, 12)
fig.subplots_adjust(left=0.4, bottom=None, right=None, top=None, wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1);
ax1.barh(list(range(1, len(total_alarm_list)+1)), alarm_stats_cum_al.loc['median duration (sec)', :], color = 'blue')
plt.ylabel("Alarms", fontsize  = 22)
plt.xlabel("seconds", fontsize  = 22)
plt.title("Median duration of alarm events" , fontsize = 26)
ax1.tick_params(which = 'both', labelsize=14)
plt.yticks([i+1.5  for i, _ in enumerate(total_alarm_list)], total_alarm_list,  rotation = 'horizontal')
plt.grid()

fig.savefig('%s/%s' % (DIR_WRITE, 'median_events_al.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

Calculate cumulative descriptive statistics of all alarms in all recording together


In [ ]:
all_durations = [] # Series containing durations of all alarm events in all the recording
for recording in recordings:
    for alarm in alarm_list[recording]:
        all_durations.append(alarm_events[recording][alarm]['duration_seconds'])
all_durations = pd.concat(all_durations)

In [ ]:
# The total number of alarm events in all the recordings

total_count = len(all_durations)
total_count

In [ ]:
# The total number of alarm events in all the recordings per 24 hour

total_count_24H = total_count / (total_recording_time.total_seconds() / 86400)
total_count_24H

In [ ]:
# Calculate descriptive statistics (expressed in seconds)

mean_duration_total     = round(all_durations.mean(), 4)
median_duration_total   = round(all_durations.median(), 4)
sd_duration_total       = round(all_durations.std(), 4)
mad_duration_total      = round(all_durations.mad(), 4)
min_duration_total      = round(all_durations.min(), 4)
pc25_duration_total     = round(all_durations.quantile(0.25), 4)
pc75_duration_total     = round(all_durations.quantile(0.75), 4)
max_duration_total      = round(all_durations.max(), 4)

In [ ]:
alarm_stats_cum_total = DataFrame([ total_count, total_count_24H,
                                    mean_duration_total, median_duration_total,
                                    sd_duration_total, mad_duration_total, min_duration_total,      
                                    pc25_duration_total, pc75_duration_total, max_duration_total], 
                                  
                                  columns = ['all alarms in all recordings'],
                                  index =  ['total alarm events', 'total alarm events per 24 hours',
                                          'mean alarm duration (sec)', 'median alarm duration (sec)',
                                          'sd alarm duration (sec)', 'mad alarm duration (sec)',
                                          'min alarm duration (sec)', '25 centile alarm duration (sec)',
                                          '75 centile alarm duration (sec)', 'max alarm duration (sec)'])

In [ ]:
# Cumulative statistics of the whole datasett

alarm_stats_cum_total.round(2)

In [ ]:
# Write cumulative statistics to Excel file

writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'alarm_stats_cum_total.xlsx'))
alarm_stats_cum_total.to_excel(writer, 'cumulative_stats')
writer.save()

Visualise the duration of all alarm events as histogram


In [ ]:
# Histogram showing the number of alarms which were shorter than 1 minute

fig = plt.figure()
fig.set_size_inches(12, 6)
fig.subplots_adjust(left=0.4, bottom=None, right=None, top=None, wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1)
n, bins, patches = plt.hist(all_durations, bins = range(0, 60))
plt.grid(True)
plt.xlabel('Alarm duration (seconds)', fontsize = 20)
plt.ylabel('Number of events', fontsize = 20)
plt.xticks(range(0,60,2), fontsize = 10)
plt.yticks(fontsize = 10)
plt.title('Histogram of alarm durations', fontsize = 20)

fig.savefig('%s/%s' % (DIR_WRITE, 'alarm_duration_hist_1.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

In [ ]:
# Histogram showing the number of alarms which were shorter than 10 minutes

fig = plt.figure()
fig.set_size_inches(12, 6)
fig.subplots_adjust(left=0.4, bottom=None, right=None, top=None, wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1)
n, bins, patches = plt.hist(all_durations, bins = range(0, 600))
plt.grid(True)
plt.xlabel('Alarm duration (seconds)', fontsize = 20)
plt.ylabel('Number of events', fontsize = 20)
plt.xticks(range(0, 600, 60), fontsize = 10)
plt.yticks(fontsize = 10)
plt.title('Histogram of alarm durations', fontsize = 20)

fig.savefig('%s/%s' % (DIR_WRITE, 'alarm_duration_hist_2.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

In [ ]:
# Histogram showing all data with a bin size of 1minutes and log X axis

fig = plt.figure()
fig.set_size_inches(12, 6)
fig.subplots_adjust(left=0.4, bottom=None, right=None, top=None, wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1)
n, bins, patches = plt.hist(all_durations, bins = range(0, 50000, 60))
plt.grid(True)
plt.xlabel('Alarm duration (seconds)', fontsize = 20)
plt.ylabel('Number of events', fontsize = 20)
plt.xticks(range(0, 50000, 600), fontsize = 10)
plt.yticks(fontsize = 10)
plt.xscale('log')
plt.yscale('log')
plt.title('Histogram of alarm durations', fontsize = 20)

fig.savefig('%s/%s' % (DIR_WRITE, 'alarm_duration_hist_3.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

How many short alarms did occur?


In [ ]:
under_10_sec =  sorted([al for al in all_durations if al < 10])
len(under_10_sec)

In [ ]:
under_1_min =  sorted([al for al in all_durations if al <= 60])
len(under_1_min)

In [ ]:
under_10_sec_MV_low = sorted([al for al in alarm_durations_alarms['Minute volume < low limit'] if al < 10])
under_10_sec_MV_high = sorted([al for al in alarm_durations_alarms['Minute volume > high limit'] if al < 10])
under_10_sec_RR_high = sorted([al for al in alarm_durations_alarms['Respiratory rate > high limit'] if al < 10])

In [ ]:
len(under_10_sec_MV_low), len(under_10_sec_MV_high), len(under_10_sec_RR_high)

In [ ]:
# Short alarms (<10 sec) in the categories where the user sets the limits

len(under_10_sec_MV_low) + len(under_10_sec_MV_high) + len(under_10_sec_RR_high)

Check which are the longest alarms


In [ ]:
# How many alarm events are longer than 1 hour?

over_1_hour =  sorted([al for al in all_durations if al > 3600]) 
len(over_1_hour)

In [ ]:
# Which alarms were longer than one hour?

alarms_over_1_hour = []
for recording in recordings:
    for alarm in alarm_list[recording]:
        for event in alarm_events[recording][alarm]['duration_seconds']:
            if event > 3600:
                alarms_over_1_hour.append((recording, alarm, event))

alarms_over_1_hour = DataFrame(sorted(alarms_over_1_hour, key = lambda x: x[2], reverse = True), 
                               columns = ['recording', 'alarm', 'duration (seconds)'])

In [ ]:
alarms_over_1_hour

In [ ]:
alarms_over_1_hour.groupby('alarm').count()
How many alarm events are longer than 10 minutes but shorter than 1 hour?

In [ ]:
over_10_minutes =  sorted([al for al in all_durations if al > 600 and al <= 3600])
len(over_10_minutes)

In [ ]:
alarms_over_10_min = []
# which alarms were longer than 10 minutes but shorter than 1 hour
for recording in recordings:
    for alarm in alarm_list[recording]:
        for event in alarm_events[recording][alarm]['duration_seconds']:
            if event > 600 and event <= 3600:
                alarms_over_10_min.append((recording, alarm, event))

In [ ]:
alarms_over_10_min = DataFrame(sorted(alarms_over_10_min, key = lambda x: x[2], reverse = True), 
                               columns = ['recording', 'alarm', 'duration (seconds)'])

In [ ]:
alarms_over_10_min.groupby('alarm').count()

how many alarm events are longer than 1 minutes?


In [ ]:
over_1_minutes =  sorted([al for al in all_durations if al > 60 and al <= 600])
len(over_1_minutes)

In [ ]:
alarms_over_1_min = []
# which alarms were longer than 1 minutes but shorter than 10 minutes
for recording in recordings:
    for alarm in alarm_list[recording]:
        for event in alarm_events[recording][alarm]['duration_seconds']:
            if event > 60 and event <= 600:
                alarms_over_1_min.append((recording, alarm, event))
                
alarms_over_1_min = DataFrame(sorted(alarms_over_1_min, key = lambda x: x[2], reverse = True), 
                               columns = ['recording', 'alarm', 'duration (seconds)'])

In [ ]:
alarms_over_1_min.groupby('alarm').count()

In [ ]:
# Write long alarms into a multisheet Excel file

writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'long_alarms.xlsx'))
alarms_over_1_hour.to_excel(writer, 'over_1hour')
alarms_over_10_min.to_excel(writer, '10min_to_1hour')
alarms_over_1_min.to_excel(writer, '1min_to_10min')
writer.save()

Check which are the most frequent alarms


In [ ]:
# Identify the most frequent alarm events

frequent_alarms = alarm_stats_cum_al.loc['count'].sort_values(inplace = False, ascending = False)

In [ ]:
# The eight most frequent alarms

frequent_alarms[:8]

In [ ]:
# How many percent of all alarms were these 8 frequent alarms?

round(frequent_alarms[:8].sum() / frequent_alarms.sum(), 3) * 100

In [ ]:
# Write frequent alarm in an Excel file

writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'frequent_alarms.xlsx'))
DataFrame(frequent_alarms[:8]).to_excel(writer, 'frequent_alarms')
writer.save()

In [ ]:
# Number of alarms where the user sets the limits

user_set_alarms = (frequent_alarms['Minute volume < low limit'] + frequent_alarms['Minute volume > high limit'] + 
                frequent_alarms['Respiratory rate > high limit'])

int(user_set_alarms)

In [ ]:
# What proportion of all alarms were these 3 user-set alarms?

print('%.3f' % (user_set_alarms / frequent_alarms.sum()))

In [ ]:
# Frequent alarms related to VT not achieved

other_frequent_alarms = (frequent_alarms['Tidal volume < low Limit'] + frequent_alarms['Volume not constant'] + 
                frequent_alarms['Tube obstructed'])

int(other_frequent_alarms)

In [ ]:
# What proportion of all alarms were alarms related to VT not achieved?

print('%.3f' % (other_frequent_alarms / frequent_alarms.sum()))

Visualise MV and RR limit alarms

Generate dictionaries with the alarm counts (absolute and per 24H recording period) for MV low and high alarms and RR high alarms for those recordings where this occurs


In [ ]:
MV_low_count = {}
for recording in recordings:
    try:
        MV_low_count[recording] = alarm_stats[recording]['Minute volume < low limit']['number of events'].iloc[0]
    except KeyError:
        # print('No "MV_low" alarm in recording %s' % recording)
        pass

In [ ]:
MV_low_count_24H = {}
for recording in recordings:
    try:
        MV_low_count_24H[recording] = \
            alarm_stats[recording]['Minute volume < low limit']['number of event per 24h'].iloc[0]
    except KeyError:
        # print('No "MV_low" alarm in recording %s' % recording)
        pass

In [ ]:
MV_high_count = {}
for recording in recordings:
    try:
        MV_high_count[recording] = alarm_stats[recording]['Minute volume > high limit']['number of events'].iloc[0]
    except KeyError:
        # print('No "MV_high" alarm in recording %s' % recording)
        pass

In [ ]:
MV_high_count_24H = {}
for recording in recordings:
    try:
        MV_high_count_24H[recording] = alarm_stats[recording]['Minute volume > high limit']['number of event per 24h'].iloc[0]
    except KeyError:
        # print('No "MV_high" alarm in recording %s' % recording)
        pass

In [ ]:
RR_high_count = {}
for recording in recordings:
    try:
        RR_high_count[recording] = alarm_stats[recording]['Respiratory rate > high limit']['number of events'].iloc[0]
    except KeyError:
        # print('No "RR_high" alarm in recording %s' % recording)
        pass

In [ ]:
RR_high_count_24H = {}
for recording in recordings:
    try:
        RR_high_count_24H[recording] = alarm_stats[recording]['Respiratory rate > high limit']['number of event per 24h'].iloc[0]
    except KeyError:
        # print('No "RR_high" alarm in recording %s' % recording)
        pass

In [ ]:
# Plot the number of MV < low limit alarm events and write graph to file

fig = plt.figure()
fig.set_size_inches(17, 12)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1);
ax1.barh(list(range(1, len(MV_low_count)+1)), MV_low_count.values(), color = 'blue')
plt.ylabel("Recordings", fontsize  = 16)
plt.xlabel("number of alarm events", fontsize  = 16)
plt.title("MV < low limit" , fontsize = 26)
ax1.tick_params(which = 'both', labelsize=14)
plt.yticks([i+1.5  for i, _ in enumerate(MV_low_count.keys())], MV_low_count.keys(),
        rotation = 'horizontal')
plt.grid()

fig.savefig('%s/%s' % (DIR_WRITE, 'MV_low.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

In [ ]:
# Plot the number of MV < low limit alarm events normalized for 24 hours and write graph to file

fig = plt.figure()
fig.set_size_inches(17, 12)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1);
ax1.barh(list(range(1, len(MV_low_count_24H)+1)), MV_low_count_24H.values(), color = 'blue')
plt.ylabel("Recordings", fontsize  = 16)
plt.xlabel("number of alarm events per 24 hours", fontsize  = 16)
plt.title("MV < low limit" , fontsize = 26)
ax1.tick_params(which = 'both', labelsize=14)
plt.yticks([i+1.5  for i, _ in enumerate(MV_low_count_24H.keys())], MV_low_count_24H.keys(),
        rotation = 'horizontal')
plt.grid()

fig.savefig('%s/%s' % (DIR_WRITE, 'MV_low_24H.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

In [ ]:
# Plot the number of MV > low limit alarm events and write graph to file

fig = plt.figure()
fig.set_size_inches(17, 12)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1);
ax1.barh(list(range(1, len(MV_high_count)+1)), MV_high_count.values(), color = 'blue')
plt.ylabel("Recordings", fontsize  = 16)
plt.xlabel("number of alarm events", fontsize  = 16)
plt.title("MV > high limit" , fontsize = 26)
ax1.tick_params(which = 'both', labelsize=14)
plt.yticks([i+1.5  for i, _ in enumerate(MV_high_count.keys())], MV_high_count.keys(),
           rotation = 'horizontal')
plt.grid()

fig.savefig('%s/%s' % (DIR_WRITE, 'MV_high.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

In [ ]:
# Plot the number of MV > low limit alarm events and write graph to file

fig = plt.figure()
fig.set_size_inches(17, 12)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1);
ax1.barh(list(range(1, len(MV_high_count_24H)+1)), MV_high_count_24H.values(), color = 'blue')
plt.ylabel("Recordings", fontsize  = 16)
plt.xlabel("number of alarm events per 24 hours", fontsize  = 16)
plt.title("MV > high limit" , fontsize = 26)
ax1.tick_params(which = 'both', labelsize=14)
plt.yticks([i+1.5  for i, _ in enumerate(MV_high_count_24H.keys())], MV_high_count_24H.keys(),
           rotation = 'horizontal')
plt.grid()

fig.savefig('%s/%s' % (DIR_WRITE, 'MV_high_24H.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

In [ ]:
# Plot the number of RR > high limit alarm events and write graph to file

fig = plt.figure()
fig.set_size_inches(17, 12)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1);
ax1.barh(list(range(1, len(RR_high_count)+1)), RR_high_count.values(), color = 'blue')
plt.ylabel("Recordings", fontsize  = 16)
plt.xlabel("number of alarm events", fontsize  = 16)
plt.title("RR > high limit" , fontsize = 26)
ax1.tick_params(which = 'both', labelsize=14)
plt.yticks([i+1.5  for i, _ in enumerate(RR_high_count.keys())], RR_high_count.keys(),
           rotation = 'horizontal')
plt.grid()

fig.savefig('%s/%s' % (DIR_WRITE, 'RR_high.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

In [ ]:
# Plot the number of RR > high limit alarm events normalized for 24 hours and write graph to file

fig = plt.figure()
fig.set_size_inches(17, 12)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1);
ax1.barh(list(range(1, len(RR_high_count_24H)+1)), RR_high_count_24H.values(), color = 'blue')
plt.ylabel("Recordings", fontsize  = 16)
plt.xlabel("number of alarm events per 24 hours", fontsize  = 16)
plt.title("RR > high limit" , fontsize = 26)
ax1.tick_params(which = 'both', labelsize=14)
plt.yticks([i+1.5  for i, _ in enumerate(RR_high_count_24H.keys())], 
           RR_high_count_24H.keys(), rotation = 'horizontal')
plt.grid()

fig.savefig('%s/%s' % (DIR_WRITE, 'RR_high_24H.jpg'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)

Investigate the relationship of MV and RR parameter readings, ventilation settings and alarm settings


In [ ]:
for recording in recordings:
    slow_measurements[recording] = pd.concat([slow_measurements[recording],
            vent_settings_2[recording], alarm_settings_2[recording]], axis = 0, join = 'outer')
    slow_measurements[recording].sort_index(inplace = True)

In [ ]:
for recording in recordings:
    slow_measurements[recording] = slow_measurements[recording].fillna(method = 'pad')

In [ ]:
def minute_volume_plotter(rec, ylim = False):
    '''
    Plots the total minute volumme (using the data obtained with 1/sec sampling rate) 
    together with the "MV low" and "MV high" alarm limits
    Displays the plot
    
    '''
    if ylim:
        ymax =  ylim
    else:
        ymax = slow_measurements[rec]['MV_high_weight'].max() + 0.3
    
    fig = plt.figure()
    fig.set_size_inches(12, 8)
    fig.subplots_adjust(left=None, bottom=None, right=None, top=None,
    wspace=None, hspace=0.7)
    ax1 = fig.add_subplot(1, 1, 1);
    slow_measurements[rec]['MV_kg'].plot(ax = ax1, color = 'blue', ylim = [0, ymax] );
    slow_measurements[rec]['MV_low_weight'].plot(ax = ax1, color = 'green', linewidth = 3, ylim = [0, ymax] );
    slow_measurements[rec]['MV_high_weight'].plot(ax = ax1, color = 'red', linewidth = 3, ylim = [0, ymax] );
    ax1.set_title('Minute volume - %s' % rec, size = 22, color = 'black')
    ax1.set_xlabel('Time', size = 22, color = 'black')
    ax1.set_ylabel('L/kg/min', size = 22, color = 'black')
    ax1.grid('on', linestyle='-', linewidth=0.5, color = 'gray')
    ax1.legend(['MV_kg', 'alarm_low', 'alarm_high']);

In [ ]:
minute_volume_plotter('DG003')

In [ ]:
def minute_volume_plotter_2(rec, ylim = False, version = ''):
    '''
    Plots the total minute volumme (using the data obtained with 1/sec sampling rate) 
    together with the "MV low" and "MV high" alarm limits
    Writes the plot to file (does not display the plot)
    
    '''
    if ylim:
        ymax =  ylim
    else:
        ymax = slow_measurements[rec]['alarm_MV_high_weight'].max() + 0.3
    
    fig = plt.figure()
    fig.set_size_inches(12, 8)
    fig.subplots_adjust(left=None, bottom=None, right=None, top=None,
    wspace=None, hspace=0.7)
    ax1 = fig.add_subplot(1, 1, 1);
    slow_measurements[rec]['MV_kg'].plot(ax = ax1, color = 'blue', ylim = [0, ymax] );
    slow_measurements[rec]['alarm_MV_low_weight'].plot(ax = ax1, color = 'green', linewidth = 3, ylim = [0, ymax] );
    slow_measurements[rec]['alarm_MV_high_weight'].plot(ax = ax1, color = 'red', linewidth = 3,  ylim = [0, ymax] );
    ax1.set_title('Minute volume - %s' % rec, size = 22, color = 'black')
    ax1.set_xlabel('Time', size = 22, color = 'black')
    ax1.set_ylabel('L/kg/min', size = 22, color = 'black')
    ax1.grid('on', linestyle='-', linewidth=0.5, color = 'gray')
    ax1.legend(['MV_kg', 'alarm_low', 'alarm_high']);

    fig.savefig('%s/%s_%s%s.jpg' % (dir_write, 'minute_volume', rec, version), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)
    plt.close(fig)
# Writing all minute volume plots to image files for recording in recordings: minute_volume_plotter_2(recording)

In [ ]:
def resp_rate_plotter(rec, ylim = False):
    '''
    Plots the total reapiratory rate (using the data obtained with 1/sec sampling rate) 
    together with the set backup rate and "RR high" alarm limits
    Displays the plot
    
    '''
    if ylim:
        ymax =  ylim
    else:
        ymax = slow_measurements[rec]['5001|RR [1/min]'].max() + 10
    
    fig = plt.figure()
    fig.set_size_inches(12, 8)
    fig.subplots_adjust(left=None, bottom=None, right=None, top=None,
    wspace=None, hspace=0.7)
    ax1 = fig.add_subplot(1, 1, 1);
    slow_measurements[rec]['5001|RR [1/min]'].plot(ax = ax1, color = 'blue', ylim = [0, ymax] );
    slow_measurements[rec]['RR_high'].plot(ax = ax1, color = 'red', linewidth = 3, ylim = [0, ymax] );
    slow_measurements[rec]['RR_set'].plot(ax = ax1, color = 'green', linewidth = 3, ylim = [0, ymax] );
    ax1.set_title('Respiratory rate - %s' % rec, size = 22, color = 'black')
    ax1.set_xlabel('Time', size = 22, color = 'black')
    ax1.set_ylabel('1/min', size = 22, color = 'black')
    ax1.grid('on', linestyle='-', linewidth=0.5, color = 'gray')
    ax1.legend(['RR', 'alarm_high', 'RR_set']);

In [ ]:
resp_rate_plotter('DG003')

In [ ]:
def resp_rate_plotter_2(rec, ylim = False, version = ''):
    '''
    Plots the total reapiratory rate (using the data obtained with 1/sec sampling rate) 
    together with the set backup rate and "RR high" alarm limits
    Writes the plots to files (does not display the plot)
    
    '''
    if ylim:
        ymax =  ylim
    else:
        ymax = slow_measurements[rec]['5001|RR [1/min]'].max() + 10
    
    fig = plt.figure()
    fig.set_size_inches(12, 8)
    fig.subplots_adjust(left=None, bottom=None, right=None, top=None,
    wspace=None, hspace=0.7)
    ax1 = fig.add_subplot(1, 1, 1);
    slow_measurements[rec]['5001|RR [1/min]'].plot(ax = ax1, color = 'blue', ylim = [0, ymax] );
    slow_measurements[rec]['alarm_RR_high'].plot(ax = ax1, color = 'red', linewidth = 3, ylim = [0, ymax] );
    slow_measurements[rec]['RR_set'].plot(ax = ax1, color = 'green', linewidth = 3, ylim = [0, ymax] );
    ax1.set_title('Respiratory rate - %s' % rec, size = 22, color = 'black')
    ax1.set_xlabel('Time', size = 22, color = 'black')
    ax1.set_ylabel('1/min', size = 22, color = 'black')
    ax1.grid('on', linestyle='-', linewidth=0.5, color = 'gray')
    ax1.legend(['RR', 'alarm_high', 'RR_set'])
    
    fig.savefig('%s/%s_%s%s.jpg' % (dir_write, 'resp_rate', rec, version), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='jpg',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)
    plt.close(fig)
# Writing all respiratory rate plots to image files for recording in recordings: resp_rate_plotter_2(recording)

Create the tables and figures of the paper

Table 1


In [ ]:
clinical_details_for_paper = clinical_details[['Gestation', 'Birth weight', 'Current weight', 'Main diagnoses']]
clinical_details_for_paper = clinical_details_for_paper.loc[recordings]
# clinical_details_for_paper

In [ ]:
vent_modes_all = {}
for recording in recordings:
    vent_modes_all[recording] = vent_modes_selected[recording].Text.unique()
    vent_modes_all[recording] = [mode[5:] for mode in vent_modes_all[recording] if mode.startswith(' Mode')]
    
vent_modes_all = DataFrame([vent_modes_all]).T
vent_modes_all.columns = ['Ventilation modes']
vent_modes_all = vent_modes_all.loc[recordings]
# vent_modes_all

In [ ]:
recording_duration_hours_all = DataFrame([recording_duration_hours]).T
recording_duration_hours_all.columns = ['Recording duration (hours)']

In [ ]:
Table_1 = recording_duration_hours_all.join([clinical_details_for_paper, vent_modes_all])

In [ ]:
Table_1

In [ ]:
writer = pd.ExcelWriter('%s/%s' % (DIR_WRITE, 'Table_1.xlsx'))
Table_1.to_excel(writer)
writer.save()

Figure 1


In [ ]:
rec = 'DG032_2'
filetype = 'jpg'
dpi = 300

alarm_state = alarm_states[rec]
numbered = Series(np.zeros(len(alarm_state)), index = alarm_state.index)
for i in range(1, len(alarm_state)):
    if alarm_state.iloc[i]['State New'] == 'Active':
        numbered[i] = alarm_list[rec].index(alarm_state.iloc[i]['Id']) + 1
    
fig = plt.figure()
fig.set_size_inches(10, 4)
fig.subplots_adjust(left=0.4, bottom=None, right=None, top=None, wspace=None, hspace=None)

ax1 = fig.add_subplot(1, 1, 1);
ax1.plot(alarm_state.index,  numbered, '|', color = 'red', markersize = 14, markeredgewidth = 0.5 )
plt.xlabel("Time", fontsize  = 14)
plt.title(rec)
plt.yticks([i+1  for i, _ in enumerate(alarm_list[rec])], alarm_list[rec], fontsize = 14);
plt.xticks(fontsize = 8)
                                                     
plt.ylim(0.5, len(alarm_list[rec]) + 0.5)
    
fig.savefig('%s/%s.jpg' % (DIR_WRITE, 'Figure_1a'), dpi=dpi, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format= filetype,
        transparent=False, bbox_inches=None, pad_inches=0.1, frameon=True)

In [ ]:
rec = 'DG032_2'
filetype = 'jpg'
dpi = 300

fig = plt.figure()
fig.set_size_inches(8, 4)
fig.subplots_adjust(left=0.5, bottom=None, right=None, top=None, wspace=None, hspace= None)
ax1 = fig.add_subplot(1, 1, 1)
xs = [i + 0.1 for i, _ in enumerate(alarm_list[rec])]
stats = []
for alarm in alarm_list[rec]:
    stats.append(alarm_stats[rec][alarm]['percentage of recording length (%)'])
stats_all = pd.concat(stats)
plt.barh(xs, stats_all, color = 'red')
plt.xlabel("% of total recording time", fontsize  = 14)
plt.title(rec)
plt.yticks([i + 0.5 for i, _ in enumerate(alarm_list[rec])], alarm_list[rec], fontsize = 14)
plt.xticks(fontsize = 14);
    
fig.savefig('%s/%s.jpg' % (DIR_WRITE, 'Figure_1b'), dpi=dpi, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format= filetype,
        transparent=False, bbox_inches=None, pad_inches=0.1, frameon=True)

In [ ]:
rec = 'DG032_2'
filetype = 'tiff'
dpi = 300

alarm_state = alarm_states[rec]
numbered = Series(np.zeros(len(alarm_state)), index = alarm_state.index)
for i in range(1, len(alarm_state)):
    if alarm_state.iloc[i]['State New'] == 'Active':
        numbered[i] = alarm_list[rec].index(alarm_state.iloc[i]['Id']) + 1
    
fig = plt.figure()
fig.set_size_inches(9, 7)
fig.subplots_adjust(left=0.4, bottom=None, right=None, top=None, wspace=None, hspace=0.3)

ax1 = fig.add_subplot(2, 1, 1);
ax1.plot(alarm_state.index,  numbered, '|', color = 'red', markersize = 10, markeredgewidth = 0.5 )
plt.xlabel("Time", fontsize  = 12)
plt.title(rec)
plt.yticks([i+1  for i, _ in enumerate(alarm_list[rec])], alarm_list[rec], fontsize = 12);
plt.xticks(fontsize = 8)
plt.ylim(0.5, len(alarm_list[rec]) + 0.5)

ax1 = fig.add_subplot(2, 1, 2)
xs = [i + 0.1 for i, _ in enumerate(alarm_list[rec])]
stats = []
for alarm in alarm_list[rec]:
    stats.append(alarm_stats[rec][alarm]['percentage of recording length (%)'])
stats_all = pd.concat(stats)
plt.barh(xs, stats_all, color = 'red')
plt.xlabel("% of total recording time", fontsize  = 12)
plt.title(rec)
plt.yticks([i + 0.5 for i, _ in enumerate(alarm_list[rec])], alarm_list[rec], fontsize = 12)
plt.xticks(fontsize = 8);
    
fig.savefig('%s/%s.tiff' % (DIR_WRITE, 'Figure_1'), dpi=dpi, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format= filetype,
        transparent=False, bbox_inches=None, pad_inches=0.1, frameon=True)

Figure 2


In [ ]:
rec = 'DG003'
filetype = 'jpg'
dpi = 300

ymax = slow_measurements[rec]['MV_high_weight'].max() + 0.3
    
fig = plt.figure()
fig.set_size_inches(8, 6)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None,
    wspace=None, hspace=None)
ax1 = fig.add_subplot(1, 1, 1);
slow_measurements[rec]['MV_kg'].plot(ax = ax1, color = 'blue', ylim = [0, ymax] );
slow_measurements[rec]['MV_low_weight'].plot(ax = ax1, color = 'green', linewidth = 3, ylim = [0, ymax] );
slow_measurements[rec]['MV_high_weight'].plot(ax = ax1, color = 'red', linewidth = 3,  ylim = [0, ymax] );
ax1.set_title(rec, size = 14, color = 'black')
ax1.set_xlabel('Time', size = 14, color = 'black')
ax1.set_ylabel('L/min/kg', size = 14, color = 'black')
ax1.tick_params(which = 'both', labelsize=12)
ax1.grid('on', linestyle='-', linewidth=0.5, color = 'gray')
ax1.legend(['MV_kg', 'alarm_low', 'alarm_high']);

fig.savefig('%s/%s.jpg' % (DIR_WRITE, 'Figure_2a_color'), dpi=dpi, facecolor='w', edgecolor='w',
    orientation='portrait', papertype=None, format= filetype,
    transparent=False, bbox_inches=None, pad_inches=0.1, frameon=True)

In [ ]:
rec = 'DG003'
filetype = 'jpg'
dpi = 300

ymax = slow_measurements[rec]['MV_high_weight'].max() + 0.3
    
fig = plt.figure()
fig.set_size_inches(8, 6)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None,
    wspace=None, hspace=None)
ax1 = fig.add_subplot(1, 1, 1);

slow_measurements[rec]['MV_kg'].plot(ax = ax1, color = 'black', alpha = 0.6, ylim = [0, ymax] );
slow_measurements[rec]['MV_low_weight'].plot(ax = ax1, color = 'black', linewidth = 3, ylim = [0, ymax] );
slow_measurements[rec]['MV_high_weight'].plot(ax = ax1, color = 'black', linewidth = 3,  ylim = [0, ymax] );

ax1.set_title(rec, size = 14, color = 'black')
ax1.set_xlabel('Time', size = 14, color = 'black')
ax1.set_ylabel('L/min/kg', size = 14, color = 'black')
ax1.tick_params(which = 'both', labelsize=12)
ax1.grid('on', linestyle='-', linewidth=0.5, color = 'gray')
ax1.legend(['MV_kg', 'alarm_low', 'alarm_high']);

fig.savefig('%s/%s.jpg' % (DIR_WRITE, 'Figure_2a_bw'), dpi=dpi, facecolor='w', edgecolor='w',
    orientation='portrait', papertype=None, format= filetype,
    transparent=False, bbox_inches=None, pad_inches=0.1, frameon=True)

In [ ]:
rec = 'DG041'
filetype = 'jpg'
dpi = 300

ymax = slow_measurements[rec]['5001|RR [1/min]'].max() + 15
    
fig = plt.figure()
fig.set_size_inches(8, 6)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None,
wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1);
    
slow_measurements[rec]['5001|RR [1/min]'].plot(ax = ax1, color = 'blue', ylim = [0, ymax] );
slow_measurements[rec]['RR_high'].plot(ax = ax1, color = 'red', linewidth = 3, ylim = [0, ymax] );
slow_measurements[rec]['RR_set'].plot(ax = ax1, color = 'green', linewidth = 3, ylim = [0, ymax] );

ax1.set_title(rec, size = 14, color = 'black')
ax1.set_xlabel('Time', size = 14, color = 'black')
ax1.set_ylabel('1/min', size = 14, color = 'black')
ax1.grid('on', linestyle='-', linewidth=0.5, color = 'gray')
ax1.legend(['RR', 'alarm_high', 'RR_set'])
    
fig.savefig('%s/%s.jpg' % (DIR_WRITE, 'Figure_2b_color'), dpi=dpi, facecolor='w', edgecolor='w',
    orientation='portrait', papertype=None, format= filetype,
    transparent=False, bbox_inches=None, pad_inches=0.1, frameon=True)

In [ ]:
rec = 'DG041'
filetype = 'jpg'
dpi = 300

ymax = slow_measurements[rec]['5001|RR [1/min]'].max() + 15
    
fig = plt.figure()
fig.set_size_inches(8, 6)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None,
wspace=None, hspace=0.7)
ax1 = fig.add_subplot(1, 1, 1);
    
slow_measurements[rec]['5001|RR [1/min]'].plot(ax = ax1, color = 'black', alpha = 0.6, ylim = [0, ymax] );
slow_measurements[rec]['RR_high'].plot(ax = ax1, color = 'black', linewidth = 3, ylim = [0, ymax] );
slow_measurements[rec]['RR_set'].plot(ax = ax1, color = 'black', linewidth = 3, ylim = [0, ymax] );

ax1.set_title(rec, size = 14, color = 'black')
ax1.set_xlabel('Time', size = 14, color = 'black')
ax1.set_ylabel('1/min', size = 14, color = 'black')
ax1.grid('on', linestyle='-', linewidth=0.5, color = 'gray')
ax1.legend(['RR', 'alarm_high', 'RR_set'])
    
fig.savefig('%s/%s.jpg' % (DIR_WRITE, 'Figure_2b_bw'), dpi=dpi, facecolor='w', edgecolor='w',
    orientation='portrait', papertype=None, format= filetype,
    transparent=False, bbox_inches=None, pad_inches=0.1, frameon=True)

In [ ]:
rec0 = 'DG003'
rec1 = 'DG041'
filetype = 'tiff'
dpi = 300

ymax0 = slow_measurements[rec0]['MV_high_weight'].max() + 0.3
ymax1 = slow_measurements[rec1]['5001|RR [1/min]'].max() + 15

fig = plt.figure()
fig.set_size_inches(6, 9)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=0.3)

ax0 = fig.add_subplot(2, 1, 1);
slow_measurements[rec0]['MV_kg'].plot(ax = ax0, color = 'blue', ylim = [0, ymax0] );
slow_measurements[rec0]['MV_low_weight'].plot(ax = ax0, color = 'green', linewidth = 3, ylim = [0, ymax0] );
slow_measurements[rec0]['MV_high_weight'].plot(ax = ax0, color = 'red', linewidth = 3,  ylim = [0, ymax0] );
ax0.set_title(rec0, size = 12, color = 'black')
ax0.set_xlabel('', size = 12, color = 'black')
ax0.set_ylabel('L/min/kg', size = 12, color = 'black')
ax0.tick_params(which = 'both', labelsize=10)
ax0.grid('on', linestyle='-', linewidth=0.5, color = 'gray')
ax0.legend(['MV_kg', 'alarm_low', 'alarm_high']);

ax1 = fig.add_subplot(2, 1, 2);    
slow_measurements[rec1]['5001|RR [1/min]'].plot(ax = ax1, color = 'blue', ylim = [0, ymax1] );
slow_measurements[rec1]['RR_high'].plot(ax = ax1, color = 'red', linewidth = 3, ylim = [0, ymax1] );
slow_measurements[rec1]['RR_set'].plot(ax = ax1, color = 'green', linewidth = 3, ylim = [0, ymax1] );
ax1.set_title(rec1, size = 12, color = 'black')
ax1.set_xlabel('Time', size = 12, color = 'black')
ax1.set_ylabel('1/min', size = 12, color = 'black')
ax1.tick_params(which = 'both', labelsize=10)
ax1.grid('on', linestyle='-', linewidth=0.5, color = 'gray')
ax1.legend(['RR', 'alarm_high', 'RR_set'], loc = 4)
    
fig.savefig('%s/%s.tiff' % (DIR_WRITE, 'Figure_2'), dpi=dpi, facecolor='w', edgecolor='w',
    orientation='portrait', papertype=None, format= filetype,
    transparent=False, bbox_inches=None, pad_inches=0.1, frameon=True)

Figure 3


In [ ]:
# Histogram showing the number of alarms which were shorter than 1 minute
fig = plt.figure()
fig.set_size_inches(7, 5)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)
ax1 = fig.add_subplot(1, 1, 1)
n, bins, patches = plt.hist(all_durations, bins = range(0, 60))
plt.grid(True)
plt.xlabel('Alarm duration (seconds)', fontsize = 12)
plt.ylabel('Number of alarm events', fontsize = 12)
plt.xticks(range(0,60,4), fontsize = 12)
plt.yticks(fontsize = 12)
plt.title('Histogram of alarm durations', fontsize = 12)

fig.savefig('%s/%s' % (DIR_WRITE, 'Figure_3.tiff'), dpi=300, facecolor='w', edgecolor='w',
        orientation='portrait', papertype=None, format='tiff',
        transparent=False, bbox_inches=None, pad_inches=0.1,
        frameon=True)