In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.ticker as mtick
import seaborn as sns

%matplotlib inline
fig_size = [16, 7]
plt.rcParams["figure.figsize"] = fig_size

In [2]:
# Load data
filepath = "data/data.csv"
raw_data = pd.read_csv(filepath, dayfirst=True, parse_dates=[["Date", "Time"]])

# Datetime processing
raw_data["CW"] = raw_data.Date_Time.dt.weekofyear
data = raw_data.set_index(pd.DatetimeIndex(raw_data.Date_Time)).drop("Date_Time", axis=1)

# First and last day of measurements for report heading
first_day = data.index[0].strftime("%d.%m.%Y")
last_day = data.index[-1].strftime("%d.%m.%Y")

data.head()


Out[2]:
Sys Dia Pulse CW
Date_Time
2017-07-15 09:16:00 148 84 57 28
2017-07-15 19:24:00 159 92 75 28
2017-07-15 22:23:00 123 83 77 28
2017-07-16 09:14:00 124 81 68 28
2017-07-16 15:16:00 121 79 70 28

Report - Blood Pressure Monitoring

Measurements between {{first_day}} and {{last_day}}

Blood Pressure & Pulse Values

Visualization


In [3]:
# Plot Util 

def make_week_plot(week, df):
    """ Creates plot object of weekly pressure and pulse values
    :Param week: calendar week [Int]
    :Param df: pd.Dataframe of pressure and pulse values per week
    :Return plt: Pyplot object
    """
    sns.set_style("darkgrid")
    fig, ax = plt.subplots()

    for ix, row in df.iterrows():
        # Pulse point marker
        pulse_plot, = ax.plot(ix, row.Pulse, 
                             marker="D", color="m", linestyle = "None", label="Pulse")
        # Sys point marker
        sys_plot, = ax.plot(ix, row.Sys,
                           marker="v", color="b", linestyle = "None", label="Systolic")
        # Dia point marker
        dia_plot, = ax.plot(ix, row.Dia,
                           marker="^", color="b", linestyle = "None", label="Diastolic")
        # Vertical line between points
        vert_plot = ax.axvline(x=ix, ymin=row.Dia/220, ymax=row.Sys/220, 
                               color="b")

    # X Axis enhancements
    ax.xaxis.set_minor_locator(mdates.DayLocator())
    ax.xaxis.set_minor_formatter(mdates.DateFormatter("\n\n\n\n%d\n%a"))
    ax.xaxis.grid(True, which="minor")
    for xmin in ax.xaxis.get_minorticklocs():
        ax.axvline(x=xmin, linestyle="-.", linewidth=1, color="k", alpha=0.4)
    ax.xaxis.set_major_locator(mdates.HourLocator(interval=2))
    ax.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
    plt.xticks(rotation=270)

    # Y Axis enhancements
    plt.yticks(range(0, 221, 20))

    # Title
    ax.set_title("Calendar Week " + str(week), fontsize= 15, fontweight="bold")
    
    # Legend
    legend = plt.legend([sys_plot, dia_plot, pulse_plot], ["Systolic", "Diastolic", "Pulse"],
                        loc=4, markerscale=1.6, frameon=True, fontsize=13)
    frame = legend.get_frame()
    frame.set_color("w")
    
    # Layout
    plt.tight_layout()
    
    return plt

In [4]:
for k,v in data.groupby("CW"):
    p = make_week_plot(week=k, df=v)
    p.show()


Metrices


In [5]:
# Metrices Utils

def make_metrices_dict(df):
    """ Creates dict of standard metrices and corresponding values
    :Param data: pd.Dataframe of pressure values
    :Return metrices dict: dict with metrices and processed values 
    """
    metrices_dict = {}

    #number of measures
    metrices_dict["Number of Measures"] = df.shape[0]
    
    #mean
    metrices_dict["Systolic mean"] = "{0:.2f}".format(df.Sys.mean())
    metrices_dict["Diastolic mean"] = "{0:.2f}".format(df.Dia.mean())

    #sys max min
    metrices_dict["Systolic max"] = df.Sys.max()
    metrices_dict["Systolic min"] = df.Sys.min()

    #dia max min
    metrices_dict["Diastolic max"] = df.Dia.max()
    metrices_dict["Diastolic min"] = df.Dia.min()
    
    #count of high / low blood pressure measures
    metrices_dict["High Pressure Measures"] = df[(df.Sys > 139) | (df.Dia > 89)].count()[0]
    metrices_dict["High Pressure Measures Rate"] = "{:.0%}".format(metrices_dict["High Pressure Measures"] / 
                                                                    metrices_dict["Number of Measures"])
    metrices_dict["Low Pressure Measures"] = df[(df.Sys < 100) | (df.Dia < 60)].count()[0]
    metrices_dict["Low Pressure Measures Rate"] = "{:.0%}".format(metrices_dict["Low Pressure Measures"] / 
                                                                    metrices_dict["Number of Measures"])
    
    #pulse measures
    metrices_dict["Pulse mean"] = "{0:.2f}".format(df.Pulse.mean())
    metrices_dict["Pulse max"] = df.Pulse.max()
    metrices_dict["Pulse min"] = df.Pulse.min()
    
    return metrices_dict

Total


In [6]:
# Metrices Total
metrices_total = make_metrices_dict(data)

metrices_table_total = pd.DataFrame.from_dict(metrices_total, orient="index").rename(columns={0: "Value"})
metrices_table_total


Out[6]:
Value
Number of Measures 57
Systolic mean 129.05
Diastolic mean 81.21
Systolic max 159
Systolic min 101
Diastolic max 92
Diastolic min 73
High Pressure Measures 11
High Pressure Measures Rate 19%
Low Pressure Measures 0
Low Pressure Measures Rate 0%
Pulse mean 72.81
Pulse max 97
Pulse min 57

Per Week


In [7]:
# Metrices per Week
metrices_weeks = pd.DataFrame()

for k,v in data.groupby("CW"):
    metrices_week = pd.DataFrame.from_dict(make_metrices_dict(v), orient="index")
    metrices_weeks = pd.concat([metrices_weeks, metrices_week], 1, ignore_index=True)

metrices_weeks.columns = data.CW.unique()
metrices_weeks


Out[7]:
28 29 30 31
Number of Measures 5 14 20 18
Systolic mean 135.00 126.29 130.50 127.94
Diastolic mean 83.80 81.79 80.35 81.00
Systolic max 159 156 148 150
Systolic min 121 107 108 101
Diastolic max 92 91 89 87
Diastolic min 79 75 73 75
High Pressure Measures 2 3 4 2
High Pressure Measures Rate 40% 21% 20% 11%
Low Pressure Measures 0 0 0 0
Low Pressure Measures Rate 0% 0% 0% 0%
Pulse mean 69.40 75.21 71.70 73.11
Pulse max 77 88 88 97
Pulse min 57 62 59 61

Data Table


In [8]:
# Data table
data_table = data
data_table.drop("CW", 1, inplace=True)
data_table.index.rename("ToM", inplace=True)

#with pd.option_context('display.max_rows', 999, 'display.max_columns', 5):
#    print df
    
pd.option_context("display.max_rows", 200)
data_table


Out[8]:
Sys Dia Pulse
ToM
2017-07-15 09:16:00 148 84 57
2017-07-15 19:24:00 159 92 75
2017-07-15 22:23:00 123 83 77
2017-07-16 09:14:00 124 81 68
2017-07-16 15:16:00 121 79 70
2017-07-17 06:45:00 123 76 67
2017-07-17 15:04:00 132 81 79
2017-07-17 21:00:00 136 87 76
2017-07-18 08:20:00 131 91 62
2017-07-18 14:04:00 139 83 65
2017-07-21 07:41:00 124 79 86
2017-07-21 14:56:00 111 82 88
2017-07-21 20:25:00 112 78 77
2017-07-22 09:52:00 107 84 72
2017-07-22 14:59:00 124 81 72
2017-07-22 20:51:00 108 83 79
2017-07-23 10:32:00 120 75 72
2017-07-23 13:53:00 156 76 77
2017-07-23 20:03:00 145 89 81
2017-07-24 09:12:00 148 85 65
2017-07-24 13:04:00 140 79 72
2017-07-24 20:59:00 144 86 70
2017-07-25 08:55:00 112 75 69
2017-07-25 15:04:00 139 80 80
2017-07-25 21:44:00 115 85 70
2017-07-26 09:33:00 127 73 69
2017-07-26 15:15:00 127 77 77
2017-07-27 07:50:00 124 76 61
2017-07-27 15:16:00 128 77 76
2017-07-27 21:52:00 132 78 66
2017-07-28 08:12:00 134 82 59
2017-07-28 13:49:00 132 78 79
2017-07-28 21:34:00 139 82 73
2017-07-29 10:29:00 136 89 72
2017-07-29 14:27:00 124 78 64
2017-07-29 21:36:00 125 80 77
2017-07-30 10:04:00 140 86 66
2017-07-30 14:28:00 136 80 81
2017-07-30 21:21:00 108 81 88
2017-07-31 09:34:00 116 75 73
2017-07-31 16:20:00 150 86 97
2017-07-31 20:50:00 131 75 74
2017-08-01 08:38:00 127 81 63
2017-08-01 14:17:00 120 79 79
2017-08-01 21:39:00 132 84 82
2017-08-02 09:30:00 118 76 67
2017-08-02 15:39:00 126 78 76
2017-08-02 20:57:00 137 86 86
2017-08-03 09:04:00 125 77 64
2017-08-03 14:07:00 138 81 61
2017-08-03 22:25:00 139 83 68
2017-08-04 09:06:00 119 87 69
2017-08-04 14:49:00 124 84 81
2017-08-05 10:02:00 134 81 68
2017-08-05 15:10:00 140 84 78
2017-08-06 09:44:00 126 84 63
2017-08-06 17:55:00 101 77 67