|
import altair as alt |
|
import streamlit as st |
|
import pandas as pd |
|
|
|
import strava |
|
from utils import find_default_publish_start_end_date |
|
|
|
st.set_page_config( |
|
page_title="Streamlit Activities analysis for Strava", |
|
page_icon=":safety_pin:", |
|
) |
|
|
|
strava_header = strava.header() |
|
|
|
st.header(":safety_pin: Streamlit Strava activities analysis") |
|
|
|
strava_auth = strava.authenticate(header=strava_header, stop_if_unauthenticated=False) |
|
|
|
if strava_auth is None: |
|
st.markdown("Click the \"Connect with Strava\" button at the top to login with your Strava account and get started.") |
|
st.stop() |
|
|
|
|
|
st.divider() |
|
st.header("Display shoes analysis") |
|
if 'athlete' not in st.session_state: |
|
athlete = strava.get_athlete_detail(strava_auth) |
|
st.session_state.athlete = athlete |
|
|
|
if 'dict_shoes' not in st.session_state: |
|
shoes = strava.get_shoes(st.session_state.athlete) |
|
dict_shoes = {shoe["name"]: shoe["converted_distance"] for shoe in shoes} |
|
st.session_state.dict_shoes = dict_shoes |
|
|
|
all_shoes_names = st.session_state.dict_shoes.keys() |
|
|
|
selected_shoes = st.multiselect( |
|
label="Select columns to plot", |
|
options=all_shoes_names, |
|
) |
|
|
|
distances = [st.session_state.dict_shoes[shoe_name] for shoe_name in selected_shoes] |
|
if selected_shoes: |
|
chart_data = pd.DataFrame({ |
|
'index':selected_shoes, |
|
'kilometers':distances |
|
}) |
|
st.bar_chart(chart_data) |
|
else: |
|
st.info("No column(s) selected") |
|
|
|
|
|
st.divider() |
|
st.header("Display zones on a period") |
|
|
|
default_start_date, default_end_date = find_default_publish_start_end_date() |
|
|
|
col_start_date, col_end_date = st.columns(2) |
|
with col_start_date: |
|
st.date_input("Start date", value=default_start_date, key="start_date") |
|
with col_end_date: |
|
st.date_input("End date", value=default_end_date, key="end_date") |
|
if st.session_state.start_date > st.session_state.end_date: |
|
st.error("Error: End date must fall after start date.") |
|
else: |
|
st.session_state.activities = strava.get_activities_on_period(strava_auth, [], st.session_state.start_date, st.session_state.end_date, 1) |
|
|
|
if len(st.session_state.activities) == 0: |
|
st.error("No activities found on this period") |
|
st.stop() |
|
else: |
|
activities_zones = {} |
|
number_activities_with_heartrate = 0 |
|
for activity in st.session_state.activities: |
|
if not activity["has_heartrate"]: |
|
continue |
|
try: |
|
st.session_state.activity_zones = strava.get_activity_zones(strava_auth, activity["id"])[0]["distribution_buckets"] |
|
number_activities_with_heartrate += 1 |
|
except Exception as e: |
|
st.write(e) |
|
if not activities_zones: |
|
activities_zones = {idx: zone["time"] // 60 for idx, zone in enumerate(st.session_state.activity_zones)} |
|
else: |
|
for idx, zone in enumerate(st.session_state.activity_zones): |
|
activities_zones[idx] += (zone["time"] // 60) |
|
|
|
st.info(f"You got {len(st.session_state.activities)} activities on this period and {number_activities_with_heartrate} have heart rate information.") |
|
|
|
zones_label = ["zone 1", "zone 2", "zone 3", "zone 4", "zone 5"] |
|
zones_df = pd.DataFrame({ |
|
'zones': zones_label, |
|
'minutes': activities_zones.values() |
|
}) |
|
|
|
scale = alt.Scale( |
|
domain=zones_label, |
|
range=["#008000", "#ffcf3e", "#f67200", "#ee1010", "#3f2204"], |
|
) |
|
color = alt.Color("zones:N", scale=scale) |
|
|
|
bars = ( |
|
alt.Chart(zones_df) |
|
.mark_bar() |
|
.encode( |
|
x="zones", |
|
y="minutes", |
|
color=color, |
|
) |
|
) |
|
|
|
st.altair_chart(bars, theme="streamlit", use_container_width=True) |