diff --git a/pages/2_FIT utilities.py b/pages/2_FIT utilities.py new file mode 100644 index 0000000..411ec52 --- /dev/null +++ b/pages/2_FIT utilities.py @@ -0,0 +1,28 @@ + +import streamlit as st +from pyfitness.load_data import fitfileinfo, fit2df +""" +# Welcome to Vincent's experiments with cycling data files + +#### Fit file utilities +- See fit file details +- Export to CSV +Questions, comments, contact me on discord: [Vincent.Davis](discordapp.com/users/vincent.davis) +""" + +with st.form(key="FIT file upload"): + fit_buffer_1 = st.file_uploader("Upload a FIT file", type=["fit", "FIT"], key="fit_file1") + submit_button = st.form_submit_button(label='Submit') +if submit_button: + with st.spinner("Processing..."): + fit_file = fit_buffer_1.getbuffer() + df = fit2df(fit_file) + with st.expander("Expand file details"): + if fit_file is not None: + ffi1 = fitfileinfo(fit_file) + st.write(ffi1) + st.download_button(label="Download FIT file as CSV", + data=df.to_csv(index=False).encode('utf-8'), + file_name="fit_to_csv.csv", + mime='text/csv') + diff --git a/pages/3_Compare Fit files.py b/pages/3_Compare Fit files.py new file mode 100644 index 0000000..fa8424a --- /dev/null +++ b/pages/3_Compare Fit files.py @@ -0,0 +1,90 @@ +import pandas as pd +import streamlit as st +import plotly.express as px +from pyfitness.load_data import fitfileinfo, fit2df + +""" +# Welcome to Vincent's experiments with cycling data files + +#### Compare interesting stats between two fit files +Questions, comments, contact me on discord: [Vincent.Davis](discordapp.com/users/vincent.davis) +""" + +def fit_stats(df: pd.DataFrame): + """Display the stats of a dataframe""" + st.write("Preview of the FIT file.\nYou can expand this") + st.write(df.head(10)) + st.write("Detailed stats of for each fields") + st.write(df.describe()) + for field in ['heart_rate', 'power', 'cadence', 'speed', 'distance', 'altitude', 'temperature']: + try: + st.write(f"{field} mean, without zeros: {df[df[field] > 0][field].mean()}") + st.write(f"{field} max: {df[field].max()}") + st.write(f"{field} max change: {df[field].diff().max()}") + fig1 = px.histogram(df[df[f"{field}"] > 0], x=f"{field}", nbins=50, + title=f"{field} distribution", histnorm='probability density') + st.plotly_chart(fig1, theme="streamlit", use_container_width=True) + fig2 = px.histogram(df[df[f"{field}"] > 0][f"{field}"].diff(), nbins=50, + title=f"{field} change distribution", histnorm='probability density') + st.plotly_chart(fig2, theme="streamlit", use_container_width=True) + except Exception as e: + st.write(f" Error with Field name: {field}\nError:\n{e}.") + + +col1, col2 = st.columns(2) + +with col1: + fit_buffer_1 = st.file_uploader("Upload a FIT file", type=["fit", "FIT"], key="fit_file1") + if fit_buffer_1 is not None: + fit_file1 = fit_buffer_1.getbuffer() + # Provide a CSV download option + # st.download_button(label="Download FIT file as CSV", + # data=fit_file1.to_csv(index=False).encode('utf-8'), + # file_name="fit_file1.csv", + # mime='text/csv') + + with st.expander("Expand file details"): + if fit_file1 is not None: + ffi1 = fitfileinfo(fit_file1) + st.write(ffi1) + df1 = fit2df(fit_file1) + df1['seconds'] = pd.to_datetime(df1.index).astype(int) / 10 ** 9 + df1['seconds'] = df1['seconds'].max() - df1['seconds'] + st.write("Enter start and end times") + st.write("These values will be applied to the stats below") + start_time = st.number_input('Start time in seconds', min_value=0, max_value=int(df1.seconds.max()), value=0, + step=1) + end_time = st.number_input('End time in seconds', min_value=0, max_value=int(df1.seconds.max()), + value=int(df1.seconds.max()), step=1) + df_filtered = df1[(df1.seconds >= start_time) & (df1.seconds <= end_time)] + fig = px.line(df_filtered, x="seconds", y="power") + st.plotly_chart(fig, theme="streamlit", use_container_width=True) + fit_stats(df_filtered) + +with col2: + fit_buffer_2 = st.file_uploader("Upload a FIT file", type=["fit", "FIT"], key="fit_file2") + if fit_buffer_2 is not None: + fit_file2 = fit_buffer_2.getbuffer() + + with st.expander("Expand file details"): + if fit_file2 is not None: + ffi2 = fitfileinfo(fit_file2) + st.write(ffi2) + df2 = fit2df(fit_file2) + df2['seconds'] = pd.to_datetime(df2.index).astype(int) / 10 ** 9 + df2['seconds'] = df2['seconds'].max() - df2['seconds'] + st.write("Enter start and end times") + st.write("These values will be applied to the stats below") + start_time = st.number_input('Start time in seconds', min_value=0, max_value=int(df2.seconds.max()), value=0, + step=1) + end_time = st.number_input('End time in seconds', min_value=0, max_value=int(df2.seconds.max()), + value=int(df2.seconds.max()), step=1) + df_filtered = df2[(df2.seconds >= start_time) & (df2.seconds <= end_time)] + fig = px.line(df_filtered, x="seconds", y="power") + st.plotly_chart(fig, theme="streamlit", use_container_width=True) + fit_stats(df_filtered) + # Provide a CSV download option + # st.download_button(label="Download FIT file as CSV", + # data=fit_file2.to_csv(index=False).encode('utf-8'), + # file_name="fit_file2.csv", + # mime='text/csv') diff --git a/pages/2_WAM Estimated VS Measures.py b/pages/4_WAM Estimated VS Measures.py similarity index 100% rename from pages/2_WAM Estimated VS Measures.py rename to pages/4_WAM Estimated VS Measures.py diff --git a/pages/4_Zwift Profile.py b/pages/4_Zwift Profile.py deleted file mode 100644 index 9edd242..0000000 --- a/pages/4_Zwift Profile.py +++ /dev/null @@ -1,25 +0,0 @@ -import json - -import streamlit as st - -from zp import zwiftprofile - -"""# Get your zwift profile data -This is a work in progress. Please report any issues at [pyfitness_streamlit](https://github.com/vincentdavis/pyfitness_streamlit) - -You can also contact me on discord: [Vincent](discordapp.com/users/VincentDavis#3484 - -Username and password are not stored, they are sent directly to Zwift to get your profile data as a JSON file.""" - -c1, c2 = st.columns(2) -with c1: - username = st.text_input("Username") -with c2: - password = st.text_input("Password", type="password") - -if len(username)>0 and (password is not None): - st.write(f"Getting {username} Zwift Profile, this can be a bit slow") - profile = zwiftprofile(username, password) - st.download_button(label="Download JSON file", data=json.dumps(profile, indent=2), file_name="zwift_profile.json", - mime='application/json') - st.write(profile) diff --git a/pages/5_Efficiency.py b/pages/5_Efficiency.py new file mode 100644 index 0000000..42481de --- /dev/null +++ b/pages/5_Efficiency.py @@ -0,0 +1,9 @@ + +import streamlit as st +""" +# Welcome to Vincent's experiments with cycling data files + +#### Something cool coming soon. + +Questions, comments, contact me on discord: [Vincent.Davis](discordapp.com/users/vincent.davis) +""" \ No newline at end of file diff --git a/pages/5_ZWIRCUS.py b/pages/6_ZWIRCUS.py similarity index 100% rename from pages/5_ZWIRCUS.py rename to pages/6_ZWIRCUS.py diff --git a/pages/3_ZwiftPower data.py b/pages/7_ZwiftPower data.py similarity index 100% rename from pages/3_ZwiftPower data.py rename to pages/7_ZwiftPower data.py diff --git a/streamlit_app.py b/streamlit_app.py index de68534..be7d197 100644 --- a/streamlit_app.py +++ b/streamlit_app.py @@ -10,86 +10,9 @@ This is a work in progress. -You can also contact me on discord: [Vincent](discordapp.com/users/vincent.davis) +Questions, comments, contact me on discord: [Vincent.Davis](discordapp.com/users/vincent.davis) +See option in left menu """ -def fit_stats(df: pd.DataFrame): - """Display the stats of a dataframe""" - st.write("Preview of the FIT file.\nYou can expand this") - st.write(df.head(10)) - st.write("Detailed stats of for each fields") - st.write(df.describe()) - for field in ['heart_rate', 'power', 'cadence', 'speed', 'distance', 'altitude', 'temperature']: - try: - st.write(f"{field} mean, without zeros: {df[df[field] > 0][field].mean()}") - st.write(f"{field} max: {df[field].max()}") - st.write(f"{field} max change: {df[field].diff().max()}") - fig1 = px.histogram(df[df[f"{field}"] > 0], x=f"{field}", nbins=50, - title=f"{field} distribution", histnorm='probability density') - st.plotly_chart(fig1, theme="streamlit", use_container_width=True) - fig2 = px.histogram(df[df[f"{field}"] > 0][f"{field}"].diff(), nbins=50, - title=f"{field} change distribution", histnorm='probability density') - st.plotly_chart(fig2, theme="streamlit", use_container_width=True) - except Exception as e: - st.write(f" Error with Field name: {field}\nError:\n{e}.") - - -col1, col2 = st.columns(2) - -with col1: - fit_buffer_1 = st.file_uploader("Upload a FIT file", type=["fit", "FIT"], key="fit_file1") - if fit_buffer_1 is not None: - fit_file1 = fit_buffer_1.getbuffer() - # Provide a CSV download option - # st.download_button(label="Download FIT file as CSV", - # data=fit_file1.to_csv(index=False).encode('utf-8'), - # file_name="fit_file1.csv", - # mime='text/csv') - - with st.expander("Expand file details"): - if fit_file1 is not None: - ffi1 = fitfileinfo(fit_file1) - st.write(ffi1) - df1 = fit2df(fit_file1) - df1['seconds'] = pd.to_datetime(df1.index).astype(int) / 10 ** 9 - df1['seconds'] = df1['seconds'].max() - df1['seconds'] - st.write("Enter start and end times") - st.write("These values will be applied to the stats below") - start_time = st.number_input('Start time in seconds', min_value=0, max_value=int(df1.seconds.max()), value=0, - step=1) - end_time = st.number_input('End time in seconds', min_value=0, max_value=int(df1.seconds.max()), - value=int(df1.seconds.max()), step=1) - df_filtered = df1[(df1.seconds >= start_time) & (df1.seconds <= end_time)] - fig = px.line(df_filtered, x="seconds", y="power") - st.plotly_chart(fig, theme="streamlit", use_container_width=True) - fit_stats(df_filtered) - -with col2: - fit_buffer_2 = st.file_uploader("Upload a FIT file", type=["fit", "FIT"], key="fit_file2") - if fit_buffer_2 is not None: - fit_file2 = fit_buffer_2.getbuffer() - - with st.expander("Expand file details"): - if fit_file2 is not None: - ffi2 = fitfileinfo(fit_file2) - st.write(ffi2) - df2 = fit2df(fit_file2) - df2['seconds'] = pd.to_datetime(df2.index).astype(int) / 10 ** 9 - df2['seconds'] = df2['seconds'].max() - df2['seconds'] - st.write("Enter start and end times") - st.write("These values will be applied to the stats below") - start_time = st.number_input('Start time in seconds', min_value=0, max_value=int(df2.seconds.max()), value=0, - step=1) - end_time = st.number_input('End time in seconds', min_value=0, max_value=int(df2.seconds.max()), - value=int(df2.seconds.max()), step=1) - df_filtered = df2[(df2.seconds >= start_time) & (df2.seconds <= end_time)] - fig = px.line(df_filtered, x="seconds", y="power") - st.plotly_chart(fig, theme="streamlit", use_container_width=True) - fit_stats(df_filtered) - # Provide a CSV download option - # st.download_button(label="Download FIT file as CSV", - # data=fit_file2.to_csv(index=False).encode('utf-8'), - # file_name="fit_file2.csv", - # mime='text/csv')