2023-07-26 03:37:02 +00:00
|
|
|
# %%
|
|
|
|
import dash, requests, math
|
|
|
|
from dash import dcc
|
|
|
|
from dash import html
|
|
|
|
from dash.dependencies import Output, State, Input
|
|
|
|
import pandas as pd
|
|
|
|
import plotly.express as px
|
|
|
|
from datetime import datetime, timedelta
|
|
|
|
|
|
|
|
|
|
|
|
# %%
|
|
|
|
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
|
|
|
|
|
|
|
|
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
|
|
|
|
server = app.server
|
|
|
|
# assume you have a "long-form" data frame
|
|
|
|
# see https://plotly.com/python/px-arguments/ for more options
|
|
|
|
|
|
|
|
app.layout = html.Div(children=[
|
|
|
|
# All elements from the top of the page
|
|
|
|
html.Div(style={
|
|
|
|
'display': 'flex',
|
|
|
|
'align-items': 'center',
|
|
|
|
'justify-content': 'center',
|
|
|
|
'gap': '20px',
|
|
|
|
'margin': 'auto',
|
|
|
|
'flex-wrap': 'wrap'
|
|
|
|
},children=[
|
|
|
|
dcc.DatePickerRange(
|
|
|
|
id='my-date-picker-range',
|
|
|
|
minimum_nights=30,
|
|
|
|
max_date_allowed=datetime.today().date() - timedelta(days=1),
|
|
|
|
min_date_allowed=datetime.today().date() - timedelta(days=720),
|
|
|
|
end_date=datetime.today().date() - timedelta(days=1),
|
|
|
|
start_date=datetime.today().date() - timedelta(days=365)
|
|
|
|
),
|
|
|
|
dcc.Input(id='input-on-submit', value="", placeholder='API ACCESS TOKEN', type='text'),
|
|
|
|
html.Button(id='submit-button', type='submit', children='Submit', n_clicks=0),
|
|
|
|
]),
|
|
|
|
|
|
|
|
html.Div(id='loading-div', style={'margin-top': '40px'}, children=[
|
|
|
|
dcc.Loading(
|
|
|
|
id="loading-progress",
|
|
|
|
type="default",
|
|
|
|
children=html.Div(id="loading-output-1")
|
|
|
|
),
|
|
|
|
]),
|
|
|
|
|
|
|
|
html.Div(id='output_div', children=[
|
|
|
|
|
|
|
|
dcc.Graph(
|
|
|
|
id='graph_RHR',
|
|
|
|
figure=px.line(),
|
|
|
|
config= {'displaylogo': False}
|
|
|
|
),
|
|
|
|
|
|
|
|
dcc.Graph(
|
|
|
|
id='graph_steps',
|
|
|
|
figure=px.bar(),
|
|
|
|
config= {'displaylogo': False}
|
|
|
|
),
|
|
|
|
|
|
|
|
dcc.Graph(
|
|
|
|
id='graph_activity_minutes',
|
|
|
|
figure=px.bar(),
|
|
|
|
config= {'displaylogo': False}
|
|
|
|
),
|
|
|
|
|
|
|
|
dcc.Graph(
|
|
|
|
id='graph_weight',
|
|
|
|
figure=px.line(),
|
|
|
|
config= {'displaylogo': False}
|
|
|
|
),
|
|
|
|
|
|
|
|
dcc.Graph(
|
|
|
|
id='graph_spo2',
|
|
|
|
figure=px.line(),
|
|
|
|
config= {'displaylogo': False}
|
|
|
|
),
|
|
|
|
]),
|
|
|
|
])
|
|
|
|
@app.callback(Output('graph_RHR', 'figure'), Output('graph_steps', 'figure'), Output('graph_activity_minutes', 'figure'), Output('graph_weight', 'figure'), Output('graph_spo2', 'figure'), Output("loading-output-1", "children"),
|
|
|
|
Input('submit-button', 'n_clicks'),
|
|
|
|
State('input-on-submit', 'value'), State('my-date-picker-range', 'start_date'), State('my-date-picker-range', 'end_date'),
|
|
|
|
prevent_initial_call=True
|
|
|
|
)
|
|
|
|
def update_output(n_clicks, value, start_date, end_date):
|
|
|
|
|
|
|
|
start_date = datetime.fromisoformat(start_date).strftime("%Y-%m-%d")
|
|
|
|
end_date = datetime.fromisoformat(end_date).strftime("%Y-%m-%d")
|
|
|
|
|
|
|
|
headers = {
|
|
|
|
"Authorization": "Bearer " + value,
|
|
|
|
"Accept": "application/json"
|
|
|
|
}
|
|
|
|
|
|
|
|
# Collecting data-----------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
response_heartrate = requests.get("https://api.fitbit.com/1/user/-/activities/heart/date/"+ start_date +"/"+ end_date +".json", headers=headers).json()
|
|
|
|
response_steps = requests.get("https://api.fitbit.com/1/user/-/activities/steps/date/"+ start_date +"/"+ end_date +".json", headers=headers).json()
|
|
|
|
response_weight = requests.get("https://api.fitbit.com/1/user/-/body/weight/date/"+ start_date +"/"+ end_date +".json", headers=headers).json()
|
|
|
|
response_spo2 = requests.get("https://api.fitbit.com/1/user/-/spo2/date/"+ start_date +"/"+ end_date +".json", headers=headers).json()
|
|
|
|
|
|
|
|
# Processing data-----------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
dates_list = []
|
|
|
|
dates_str_list = []
|
|
|
|
rhr_list = []
|
|
|
|
steps_list = []
|
|
|
|
weight_list = []
|
|
|
|
spo2_list = []
|
|
|
|
fat_burn_minutes_list, cardio_minutes_list, peak_minutes_list = [], [], []
|
|
|
|
|
|
|
|
for entry in response_heartrate['activities-heart']:
|
|
|
|
dates_str_list.append(entry['dateTime'])
|
|
|
|
dates_list.append(datetime.strptime(entry['dateTime'], '%Y-%m-%d'))
|
|
|
|
try:
|
|
|
|
fat_burn_minutes_list.append(entry["value"]["heartRateZones"][1]["minutes"])
|
|
|
|
cardio_minutes_list.append(entry["value"]["heartRateZones"][2]["minutes"])
|
|
|
|
peak_minutes_list.append(entry["value"]["heartRateZones"][3]["minutes"])
|
|
|
|
except KeyError as E:
|
|
|
|
fat_burn_minutes_list.append(None)
|
|
|
|
cardio_minutes_list.append(None)
|
|
|
|
peak_minutes_list.append(None)
|
|
|
|
if 'restingHeartRate' in entry['value']:
|
|
|
|
rhr_list.append(entry['value']['restingHeartRate'])
|
|
|
|
else:
|
|
|
|
rhr_list.append(None)
|
|
|
|
|
|
|
|
for entry in response_steps['activities-steps']:
|
|
|
|
steps_list.append(int(entry['value']))
|
|
|
|
|
|
|
|
for entry in response_weight["body-weight"]:
|
|
|
|
weight_list.append(float(entry['value']))
|
|
|
|
|
|
|
|
for entry in response_spo2:
|
|
|
|
spo2_list += [None]*(dates_str_list.index(entry["dateTime"])-len(spo2_list))
|
|
|
|
spo2_list.append(entry["value"]["avg"])
|
|
|
|
|
2023-07-26 03:51:55 +00:00
|
|
|
print(len(dates_list),len(rhr_list),len(steps_list),len(fat_burn_minutes_list),len(cardio_minutes_list),len(peak_minutes_list),len(weight_list),len(spo2_list))
|
|
|
|
|
2023-07-26 03:37:02 +00:00
|
|
|
df_merged = pd.DataFrame({
|
|
|
|
"Date": dates_list,
|
|
|
|
"Resting Heart Rate": rhr_list,
|
|
|
|
"Steps Count": steps_list,
|
|
|
|
"Fat Burn Minutes": fat_burn_minutes_list,
|
|
|
|
"Cardio Minutes": cardio_minutes_list,
|
|
|
|
"Peak Minutes": peak_minutes_list,
|
|
|
|
"weight": weight_list,
|
|
|
|
"SPO2": spo2_list
|
|
|
|
})
|
|
|
|
|
|
|
|
# Plotting data-----------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
fig_rhr = px.line(df_merged, x="Date", y="Resting Heart Rate", line_shape="spline", range_y=(40,80), color_discrete_sequence=["#6b3908"], title="Daily Resting Heart Rate")
|
|
|
|
fig_steps = px.bar(df_merged, x="Date", y="Steps Count", title="Daily Steps Count")
|
|
|
|
fig_activity_minutes = px.bar(df_merged, x="Date", y=["Fat Burn Minutes", "Cardio Minutes", "Peak Minutes"], title="Activity Minutes")
|
|
|
|
fig_activity_minutes.update_layout(yaxis_title='Active Minutes')
|
|
|
|
fig_weight = px.line(df_merged, x="Date", y="weight", line_shape="spline", color_discrete_sequence=["#6b3908"], title="Weight")
|
|
|
|
fig_spo2 = px.bar(df_merged, x="Date", y="SPO2", title="SPO2 Percentage", range_y=(80,100))
|
|
|
|
|
|
|
|
|
|
|
|
return fig_rhr, fig_steps, fig_activity_minutes, fig_weight, fig_spo2, ""
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
app.run_server(debug=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# %%
|