mannnon commited on
Commit
1f8cc6a
·
verified ·
1 Parent(s): 36708f1

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +122 -0
app.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import pandas as pd
3
+ import streamlit as st
4
+ import matplotlib.pyplot as plt
5
+
6
+ from zebris_extractor import extract_zebris_csv
7
+
8
+ st.set_page_config(page_title="Zebris — Profil & Seuils", layout="wide")
9
+
10
+ st.title("Zebris — Profil biomécanique & seuils individualisés")
11
+
12
+ with st.sidebar:
13
+ uploaded_files = st.file_uploader(
14
+ "Importer CSV Zebris",
15
+ type=["csv"],
16
+ accept_multiple_files=True,
17
+ )
18
+
19
+ volume_horaire = st.number_input(
20
+ "Volume horaire / semaine",
21
+ min_value=0.5,
22
+ max_value=40.0,
23
+ value=5.0,
24
+ step=0.5,
25
+ )
26
+
27
+ if not uploaded_files:
28
+ st.stop()
29
+
30
+
31
+ def avg(a, b):
32
+ if pd.isna(a) and pd.isna(b):
33
+ return np.nan
34
+ if pd.isna(a):
35
+ return float(b)
36
+ if pd.isna(b):
37
+ return float(a)
38
+ return (float(a) + float(b)) / 2
39
+
40
+
41
+ def asym(a, b):
42
+ m = avg(a, b)
43
+ if pd.isna(m) or m == 0:
44
+ return np.nan
45
+ return abs(a - b) / m * 100
46
+
47
+
48
+ def compute_metrics(row, poids):
49
+ poids_n = poids * 9.81
50
+
51
+ force = avg(row["Force talon G (N)"], row["Force talon D (N)"])
52
+ pression = avg(row["Pression talon G (N/cm²)"], row["Pression talon D (N/cm²)"])
53
+
54
+ asym_talon = asym(row["Force talon G (N)"], row["Force talon D (N)"])
55
+
56
+ return {
57
+ "force": force,
58
+ "pression": pression,
59
+ "asym": asym_talon,
60
+ }
61
+
62
+
63
+ def compute_thresholds(poids, volume):
64
+ poids_n = poids * 9.81
65
+
66
+ if volume <= 3:
67
+ f_low, f_high = 0.25, 0.40
68
+ p_low, p_high = 4, 8
69
+ elif volume <= 6:
70
+ f_low, f_high = 0.22, 0.37
71
+ p_low, p_high = 4, 7.5
72
+ else:
73
+ f_low, f_high = 0.20, 0.35
74
+ p_low, p_high = 4, 7
75
+
76
+ return {
77
+ "force_low": f_low * poids_n,
78
+ "force_high": f_high * poids_n,
79
+ "pression_low": p_low,
80
+ "pression_high": p_high,
81
+ }
82
+
83
+
84
+ dfs = []
85
+ for f in uploaded_files:
86
+ df, _ = extract_zebris_csv(f)
87
+ dfs.append(df)
88
+
89
+ df = pd.concat(dfs)
90
+
91
+ athlete = st.selectbox("Athlète", df["Nom"].unique())
92
+ df = df[df["Nom"] == athlete]
93
+
94
+ row = df.iloc[0]
95
+
96
+ poids = st.number_input("Poids", value=70.0)
97
+
98
+ metrics = compute_metrics(row, poids)
99
+ thresholds = compute_thresholds(poids, volume_horaire)
100
+
101
+ st.subheader("Seuils")
102
+
103
+ impact_df = pd.DataFrame({
104
+ "Variable": [
105
+ "Force talon",
106
+ "Pression talon",
107
+ ],
108
+ "Zone basse": [
109
+ f"< {thresholds['force_low']:.1f} N",
110
+ f"< {thresholds['pression_low']:.1f} N/cm²",
111
+ ],
112
+ "Zone normale": [
113
+ f"{thresholds['force_low']:.1f} à {thresholds['force_high']:.1f} N",
114
+ f"{thresholds['pression_low']:.1f} à {thresholds['pression_high']:.1f} N/cm²",
115
+ ],
116
+ "Zone élevée": [
117
+ f"> {thresholds['force_high']:.1f} N",
118
+ f"> {thresholds['pression_high']:.1f} N/cm²",
119
+ ],
120
+ })
121
+
122
+ st.dataframe(impact_df, use_container_width=True)