Download app.py from mannnon/seuils: direct link, hf CLI and curl.
- Browser
- Download file 4.77 kB
-
https://huggingface.co/spaces/mannnon/seuils/resolve/main/app.py
- Command line
-
hf download hf://spaces/mannnon/seuils/app.py
-
curl -L -o app.py https://huggingface.co/spaces/mannnon/seuils/resolve/main/app.py
4.77 kB
| import pandas as pd | |
| import streamlit as st | |
| st.set_page_config(page_title="Seuils individualisés - Zebris", layout="wide") | |
| st.title("Générateur de seuils individualisés") | |
| st.caption("Poids + volume horaire d'entraînement → seuils personnalisés de référence") | |
| st.subheader("Entrées athlète") | |
| c1, c2 = st.columns(2) | |
| with c1: | |
| nom = st.text_input("Nom de l'athlète", value="Lucas Martin") | |
| poids_kg = st.number_input("Poids (kg)", min_value=30.0, max_value=150.0, value=72.0, step=0.1) | |
| with c2: | |
| sport = st.text_input("Sport", value="Course sur route") | |
| volume_horaire = st.number_input("Volume horaire / semaine", min_value=0.5, max_value=30.0, value=5.0, step=0.5) | |
| poids_n = poids_kg * 9.81 | |
| # Définition de la catégorie de charge | |
| if volume_horaire <= 3: | |
| charge = "faible" | |
| elif volume_horaire <= 6: | |
| charge = "modérée" | |
| else: | |
| charge = "élevée" | |
| st.info(f"Catégorie de charge retenue : **{charge}**") | |
| # Seuils selon la charge | |
| if charge == "faible": | |
| force_bw_low = 0.75 | |
| force_bw_high = 1.00 | |
| pression_low = 20 | |
| pression_high = 26 | |
| cadence_low = 160 | |
| cadence_high = 172 | |
| contact_low = 70 | |
| contact_high = 74 | |
| flight_low = 26 | |
| flight_high = 30 | |
| asym_low = 6 | |
| asym_high = 10 | |
| rotation_low = 6 | |
| rotation_high = 10 | |
| elif charge == "modérée": | |
| force_bw_low = 0.70 | |
| force_bw_high = 0.95 | |
| pression_low = 20 | |
| pression_high = 25 | |
| cadence_low = 165 | |
| cadence_high = 176 | |
| contact_low = 69 | |
| contact_high = 73 | |
| flight_low = 27 | |
| flight_high = 31 | |
| asym_low = 5 | |
| asym_high = 9 | |
| rotation_low = 5 | |
| rotation_high = 9 | |
| else: | |
| force_bw_low = 0.65 | |
| force_bw_high = 0.90 | |
| pression_low = 20 | |
| pression_high = 24 | |
| cadence_low = 168 | |
| cadence_high = 180 | |
| contact_low = 68 | |
| contact_high = 72 | |
| flight_low = 28 | |
| flight_high = 32 | |
| asym_low = 4 | |
| asym_high = 8 | |
| rotation_low = 4 | |
| rotation_high = 8 | |
| # Conversion en Newton | |
| force_n_low = force_bw_low * poids_n | |
| force_n_high = force_bw_high * poids_n | |
| st.subheader("Résumé athlète") | |
| r1, r2, r3 = st.columns(3) | |
| with r1: | |
| st.metric("Poids", f"{poids_kg:.1f} kg") | |
| with r2: | |
| st.metric("Poids en Newton", f"{poids_n:.1f} N") | |
| with r3: | |
| st.metric("Charge", charge) | |
| st.subheader("Seuils individualisés") | |
| impact_df = pd.DataFrame({ | |
| "Variable": [ | |
| "Force talon normalisée", | |
| "Force talon convertie", | |
| "Pression talon", | |
| ], | |
| "Zone basse / faible": [ | |
| f"< {force_bw_low:.2f} BW", | |
| f"< {force_n_low:.1f} N", | |
| f"< {pression_low} N/cm²", | |
| ], | |
| "Zone attendue": [ | |
| f"{force_bw_low:.2f} à {force_bw_high:.2f} BW", | |
| f"{force_n_low:.1f} à {force_n_high:.1f} N", | |
| f"{pression_low} à {pression_high} N/cm²", | |
| ], | |
| "Zone haute / élevée": [ | |
| f"> {force_bw_high:.2f} BW", | |
| f"> {force_n_high:.1f} N", | |
| f"> {pression_high} N/cm²", | |
| ], | |
| }) | |
| dynamique_df = pd.DataFrame({ | |
| "Variable": [ | |
| "Cadence", | |
| "Temps de contact", | |
| "Temps de vol", | |
| ], | |
| "Zone basse / faible": [ | |
| f"< {cadence_low} pas/min", | |
| f"< {contact_low} %", | |
| f"< {flight_low} %", | |
| ], | |
| "Zone attendue": [ | |
| f"{cadence_low} à {cadence_high} pas/min", | |
| f"{contact_low} à {contact_high} %", | |
| f"{flight_low} à {flight_high} %", | |
| ], | |
| "Zone haute / élevée": [ | |
| f"> {cadence_high} pas/min", | |
| f"> {contact_high} %", | |
| f"> {flight_high} %", | |
| ], | |
| }) | |
| symetrie_df = pd.DataFrame({ | |
| "Variable": [ | |
| "Asymétrie force talon", | |
| "Asymétrie force avant-pied", | |
| "Asymétrie COP", | |
| "Différence rotation G/D", | |
| ], | |
| "Zone faible": [ | |
| f"< {asym_low} %", | |
| f"< {asym_low} %", | |
| f"< {asym_low} %", | |
| f"< {rotation_low}°", | |
| ], | |
| "Zone modérée": [ | |
| f"{asym_low} à {asym_high} %", | |
| f"{asym_low} à {asym_high} %", | |
| f"{asym_low} à {asym_high} %", | |
| f"{rotation_low} à {rotation_high}°", | |
| ], | |
| "Zone marquée": [ | |
| f"> {asym_high} %", | |
| f"> {asym_high} %", | |
| f"> {asym_high} %", | |
| f"> {rotation_high}°", | |
| ], | |
| }) | |
| tab1, tab2, tab3 = st.tabs(["Impact", "Dynamique", "Symétrie"]) | |
| with tab1: | |
| st.dataframe(impact_df, hide_index=True, use_container_width=True) | |
| with tab2: | |
| st.dataframe(dynamique_df, hide_index=True, use_container_width=True) | |
| with tab3: | |
| st.dataframe(symetrie_df, hide_index=True, use_container_width=True) | |
| st.subheader("Lecture méthodologique") | |
| st.write( | |
| "Ces seuils sont individualisés à partir du poids et du volume horaire d’entraînement hebdomadaire. " | |
| "Ils constituent une base de référence personnelle de l’athlète avant toute analyse ou recommandation." | |
| ) |