What does this notebook do?
import pandas as pd
import plotly.express as px
import datetime
from datetime import date
from garminconnect import (
Garmin,
GarminConnectConnectionError,
GarminConnectTooManyRequestsError,
GarminConnectAuthenticationError,
)
# Read in CSV file
df = pd.read_csv('export.csv')
# Remove "time zone offset" from "occurred_at" column and add new "occurred_at_day" column
df['occurred_at_day'] = df['occurred_at'].apply(lambda x: x[:len(x) - 15])
df['occurred_at'] = df['occurred_at'].apply(lambda x: x[:len(x) - 6])
df.head()
class | value | time | length | photo_url | description | occurred_at | body | updated_at | started_at | ended_at | created_by | occurred_at_day | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | GlucoseMeasurement | 100.0 | NaN | NaN | NaN | NaN | 2021-08-15 23:48:06 | NaN | NaN | NaN | NaN | NaN | 2021-08-15 |
1 | GlucoseMeasurement | 99.0 | NaN | NaN | NaN | NaN | 2021-08-15 23:33:06 | NaN | NaN | NaN | NaN | NaN | 2021-08-15 |
2 | GlucoseMeasurement | 99.0 | NaN | NaN | NaN | NaN | 2021-08-15 23:18:06 | NaN | NaN | NaN | NaN | NaN | 2021-08-15 |
3 | GlucoseMeasurement | 98.0 | NaN | NaN | NaN | NaN | 2021-08-15 23:03:06 | NaN | NaN | NaN | NaN | NaN | 2021-08-15 |
4 | GlucoseMeasurement | 97.0 | NaN | NaN | NaN | NaN | 2021-08-15 22:48:06 | NaN | NaN | NaN | NaN | NaN | 2021-08-15 |
# Print all days with data
daysWithData = df['occurred_at_day'].unique()
print(daysWithData)
['2021-08-15' '2021-08-14' '2021-08-13' '2021-08-12' '2021-08-11' '2021-08-10' '2021-08-09' '2021-08-08' '2021-08-07' '2021-08-06' '2021-08-05']
# Filter down to one day, pick the second day in the dataset
df = df[df['occurred_at_day']==daysWithData[2]]
day = daysWithData[2]
# Create a datasets just with glucose measurments
gm = df[df['class']=='GlucoseMeasurement']
# Create a dataset for meals and exercise, sort it
mealsExercise = df[((df['class']=='Meal') | (df['class']=='ExerciseActivity') )]
mealsExerciseSorted = mealsExercise.sort_values(by=["occurred_at"], ascending=True)
# Create a dataset with just 2 columns
gm_data = gm.filter(['occurred_at', 'value'])
# rename the columns for easier readability
gm_data.columns = ['time', 'value']
# turn time column into the index and delete time column
gm_data['time']= pd.to_datetime(gm_data['time'])
gm_data.index = gm_data['time']
del gm_data['time']
gm_data = gm_data.resample('1T').mean() # add rows for every 1 minute
gm_data = gm_data.interpolate(method='cubic') # interpolate the new 1 minute points with data
# Calculate a few metrics
threshold = 120 # this is an arbitrary threshold
above = gm_data[gm_data['value'] > threshold] # create a dataset with glucose measuremnts over threshold
minutesAboveThreshold = above.count()
print('Number of minutes above '+str(threshold)+': '+ minutesAboveThreshold.to_string(index=False))
percentageAboveThreshold = int(round(minutesAboveThreshold/(60*24)*100,0))
print("Time above Threshold = "+str(percentageAboveThreshold)+"%")
averageGlucose = int(round(gm_data['value'].mean()))
medianGlucose = int(round(gm_data['value'].median()))
print("Average Glucose = "+str(averageGlucose))
print("Median Glucose = "+str(medianGlucose))
Number of minutes above 120: 74 Time above Threshold = 5% Average Glucose = 94 Median Glucose = 91
# Get Garmin Data
# This may not be so great, defaulting to simply retrieving the last 100 activities on Garmin.
# If the day that is plotted is further in the past, this may not work.
numberOfActivities = 100
try:
# Initialize Garmin client with credentials
# Put your userID and password for https://connect.garmin.com/ here
client = Garmin("USERID", "PASSWORD")
# Login to Garmin Connect portal
client.login()
# Get running activities
allActivities = client.get_activities(0,numberOfActivities) # 0=start, numberOfActivities=limit
except (GarminConnectConnectionError, GarminConnectAuthenticationError, GarminConnectTooManyRequestsError,) as err:
print("Error occured during Garmin Connect Client init: %s" % err)
quit()
except Exception:
print("Unknown error occured during Garmin Connect Client init.")
fig = px.line(gm_data, y="value")
# add meals and exercise to the chart
yText = 55
eventColor = "green"
for index, row in mealsExerciseSorted.iterrows():
# If the activity has "run" in the description, don't use it as it is a duplicate from Garmin
if "run" in row['description']: continue
# Convert the time in pandas to something that we can use as an index for the x-axis placement
time = datetime.datetime.strptime(row['occurred_at'], '%Y-%m-%d %H:%M:%S')
# Pick a different color depending on the event
if (row['class'] == "Meal"): eventColor = "black"
else: eventColor = "green"
# draw a vertical line at the time of the meal/exercise
fig.add_shape(type="line", xref="x", yref="y", x0=time, y0=70, x1=time , y1=140, line_color=eventColor,)
# Alternate text placement so adjacent text doesn't overlap
if (yText == 55): yText = 60
else: yText = 55
# Add text
fig.add_annotation(text=row['description'], xref="x", yref="y", x=time, y=yText, showarrow=False, font=dict(color=eventColor))
# Add Garmin running activities
for i in range(numberOfActivities):
activity = allActivities[i]
# only activities that are of type "running"
if activity["activityType"]["typeKey"] == "running":
activityDateTime = activity['startTimeLocal']
activityDate = datetime.datetime.strptime(activityDateTime, "%Y-%m-%d %H:%M:%S")
if str(activityDate.date()) == day:
# draw a vertical line at the time of the running activity
fig.add_shape(type="line", xref="x", yref="y", x0=activityDateTime, y0=70, x1=activityDateTime , y1=140, line_color="green",)
# Add text
textDescr = str(activity['activityName']) + " " + str(int(round(activity['distance']/1000))) + "K run"
fig.add_annotation(text=textDescr, xref="x", yref="y", x=activityDateTime, y=65, showarrow=False, font=dict(color="green"))
# Draw a line at the threshold
fig.add_shape(type="line", xref="x", yref="y",
x0=gm_data.index[0], y0=threshold, x1=gm_data.index.max(), y1=threshold, line_color="red",)
# Show text box with summary values
fig.add_annotation(
text='Threshold = '+str(threshold)+
'<br>Minutes above Threshold = '+str(int(round(minutesAboveThreshold,0)))+
'<br>Time above Threshold = '+str(percentageAboveThreshold)+"%"+
'<br>Average Glucose = '+str(averageGlucose)+
'<br>Median Glucose = '+str(medianGlucose),
align='right', showarrow=False,
xref='paper', yref='paper', x=0.002, y=0.005,
bordercolor='black', borderwidth=1
)
# Set x and y axis title and unit
fig.update_xaxes(title_text=str(day), tickformat='%H:%M')
fig.update_yaxes(title_text='mg/dL')
fig.show()