MaxBDKT commited on
Commit
dfdc829
·
verified ·
1 Parent(s): 6ac1af8

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +106 -62
src/streamlit_app.py CHANGED
@@ -4,87 +4,131 @@ import numpy as np
4
  import plotly.graph_objects as go
5
  import os
6
 
7
- # Configuration de la page
8
- st.set_page_config(page_title="Brake_Lab_Test", layout="wide")
9
- st.title("🔬 Lab_test_visual : Analyse de Performance")
10
 
11
- # --- CHARGEMENT ---
12
  @st.cache_data
13
  def load_data():
14
- # Détection du chemin du fichier dans le dossier /src
15
  current_dir = os.path.dirname(__file__)
16
  file_path = os.path.join(current_dir, "Brake_Lab_Test_Data.xlsx")
17
-
18
- # On utilise 'Data' avec la majuscule ici
19
  data = pd.read_excel(file_path, sheet_name='Data')
20
-
21
- # Nettoyage des noms de colonnes (enlève les espaces avant/après)
22
  data.columns = data.columns.str.strip()
23
  return data
24
 
25
  try:
26
  df = load_data()
27
 
28
- # Barre latérale pour le réglage X
29
- st.sidebar.header("⚙️ Configuration")
30
- x_input = st.sidebar.slider("Valeur cible (X)", 40, 200, 100)
31
-
32
- st.info(f"Visualisation des régressions linéaires pour X entre 40 et 200")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
- # --- CRÉATION DU GRAPHIQUE ---
35
- fig = go.Figure()
36
- x_range = np.linspace(40, 200, 100)
37
-
38
- # Palette de couleurs Decathlon / Sport
39
- colors = ['#0082C3', '#E63312', '#333333', '#FFD200', '#00A14B']
 
40
 
41
- for i, (index, row) in enumerate(df.iterrows()):
42
- color = colors[i % len(colors)]
43
- model = row['model name']
44
-
45
- # Calcul des droites : y = ax + b
46
- y_dry = row['dry a'] * x_range + row['dry b']
47
- y_wet = row['wet a'] * x_range + row['wet b']
48
 
49
- # Ajout Courbe SEC (Pleine)
50
- fig.add_trace(go.Scatter(x=x_range, y=y_dry, mode='lines',
51
- name=f"{model} (Sec)", line=dict(color=color, width=3)))
52
-
53
- # Ajout Courbe HUMIDE (Pointillée)
54
- fig.add_trace(go.Scatter(x=x_range, y=y_wet, mode='lines',
55
- name=f"{model} (Wet)", line=dict(color=color, width=2, dash='dot')))
56
 
57
- # Ligne verticale pour la valeur sélectionnée
58
- fig.add_vline(x=x_input, line_width=2, line_dash="dash", line_color="red")
 
 
 
 
 
59
 
60
- fig.update_layout(
61
- height=600,
62
- xaxis_title="Entrée (Pression/Vitesse)",
63
- yaxis_title="Performance (Coefficient)",
64
- legend_title="Modèles & Conditions",
65
- hovermode="x unified"
66
- )
67
 
68
- st.plotly_chart(fig, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
- # --- TABLEAU RÉCAPITULATIF ---
71
- st.subheader(f"📊 Performances au point X = {x_input}")
72
-
73
- recap_data = []
74
- for index, row in df.iterrows():
75
- val_dry = row['dry a'] * x_input + row['dry b']
76
- val_wet = row['wet a'] * x_input + row['wet b']
77
- perte = ((val_dry - val_wet) / val_dry) * 100 if val_dry != 0 else 0
78
 
79
- recap_data.append({
80
- "Modèle": row['model name'],
81
- "Résultat Sec": round(val_dry, 3),
82
- "Résultat Humide": round(val_wet, 3),
83
- "Perte d'efficacité": f"{round(perte, 1)}%"
84
- })
85
-
86
- st.table(pd.DataFrame(recap_data))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
 
88
  except Exception as e:
89
- st.error(f"Erreur de lecture : {e}")
90
- st.warning("Vérifiez que les colonnes 'model name', 'dry a', 'dry b', 'wet a', 'wet b' sont bien présentes dans l'onglet 'Data'.")
 
4
  import plotly.graph_objects as go
5
  import os
6
 
7
+ # Page Configuration
8
+ st.set_page_config(page_title="Brake Performance Lab", layout="wide", page_icon="🚲")
 
9
 
 
10
  @st.cache_data
11
  def load_data():
 
12
  current_dir = os.path.dirname(__file__)
13
  file_path = os.path.join(current_dir, "Brake_Lab_Test_Data.xlsx")
14
+ # Reading 'Data' sheet as specified
 
15
  data = pd.read_excel(file_path, sheet_name='Data')
 
 
16
  data.columns = data.columns.str.strip()
17
  return data
18
 
19
  try:
20
  df = load_data()
21
 
22
+ # --- SIDEBAR (ADVANCED FILTERS) ---
23
+ with st.sidebar:
24
+ # Decathlon International Logo
25
+ st.image("https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Decathlon_Logo.svg/1280px-Decathlon_Logo.svg.png", width=200)
26
+ st.title("⚙️ Settings")
27
+
28
+ # 1. Lever Effort Input
29
+ x_input = st.slider("🫱 Lever Effort (N)", 40, 200, 100, help="Force applied to the brake lever in Newtons")
30
+
31
+ st.markdown("---")
32
+ st.subheader("🔍 Graph Filters")
33
+
34
+ # 2. Model Selection
35
+ all_models = df['model name'].unique().tolist()
36
+ selected_models = st.multiselect(
37
+ "Select Models",
38
+ options=all_models,
39
+ default=all_models[:2] if len(all_models) > 1 else all_models
40
+ )
41
+
42
+ # 3. Condition Selection
43
+ condition_view = st.radio(
44
+ "Conditions to display",
45
+ ["Both", "Dry only", "Wet only"],
46
+ index=0
47
+ )
48
 
49
+ # --- DIAGNOSTIC LOGIC ---
50
+ if x_input < 70:
51
+ label, color_alert = "❄️ LIGHT BRAKING", "#a1c4fd" # Light Blue
52
+ elif 70 <= x_input <= 110:
53
+ label, color_alert = "⚖️ MODERATE BRAKING", "#ffdb58" # Yellow
54
+ else:
55
+ label, color_alert = "🔥 POWERFUL BRAKING", "#ff4b4b" # Red
56
 
57
+ # Diagnostic Header
58
+ st.markdown(f"""
59
+ <div style="background-color:{color_alert}; padding:15px; border-radius:10px; text-align:center; border: 1px solid #ddd;">
60
+ <h2 style="color:black; margin:0;">{label}</h2>
61
+ <p style="color:black; font-weight:bold; margin:5px 0 0 0;">Current Lever Effort: {x_input} N</p>
62
+ </div>
63
+ """, unsafe_allow_html=True)
64
 
65
+ # --- PLOT AREA ---
66
+ col1, col2 = st.columns([3, 1])
 
 
 
 
 
67
 
68
+ with col1:
69
+ filtered_df = df[df['model name'].isin(selected_models)]
70
+
71
+ fig = go.Figure()
72
+ x_range = np.linspace(40, 200, 100)
73
+ # Decathlon-friendly color palette
74
+ colors = ['#0082C3', '#E63312', '#333333', '#00A14B', '#FFD200', '#AB63FA']
75
 
76
+ for i, (index, row) in enumerate(filtered_df.iterrows()):
77
+ color = colors[i % len(colors)]
78
+
79
+ # Linear Regression Calculation: y = ax + b
80
+ y_dry = row['dry a'] * x_range + row['dry b']
81
+ y_wet = row['wet a'] * x_range + row['wet b']
 
82
 
83
+ # DRY Trace
84
+ if condition_view in ["Both", "Dry only"]:
85
+ fig.add_trace(go.Scatter(x=x_range, y=y_dry, mode='lines',
86
+ name=f"{row['model name']} (Dry)",
87
+ line=dict(color=color, width=4),
88
+ hovertemplate="Effort: %{x}N<br>Perf: %{y:.2f}"))
89
+
90
+ # WET Trace
91
+ if condition_view in ["Both", "Wet only"]:
92
+ fig.add_trace(go.Scatter(x=x_range, y=y_wet, mode='lines',
93
+ name=f"{row['model name']} (Wet)",
94
+ line=dict(color=color, width=2, dash='dot'),
95
+ hovertemplate="Effort: %{x}N<br>Perf: %{y:.2f}"))
96
 
97
+ # Vertical line for current effort
98
+ fig.add_vline(x=x_input, line_width=3, line_dash="dash", line_color="black")
 
 
 
 
 
 
99
 
100
+ fig.update_layout(
101
+ xaxis_title="Lever Effort (N)",
102
+ yaxis_title="Braking Performance",
103
+ legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1),
104
+ plot_bgcolor='white',
105
+ hovermode="x unified"
106
+ )
107
+ st.plotly_chart(fig, use_container_width=True)
108
+
109
+ with col2:
110
+ st.subheader("💡 Analysis")
111
+ if not filtered_df.empty:
112
+ for index, row in filtered_df.iterrows():
113
+ val_dry = row['dry a'] * x_input + row['dry b']
114
+ val_wet = row['wet a'] * x_input + row['wet b']
115
+ # Drop in efficiency calculation
116
+ loss = ((val_dry - val_wet) / val_dry) * 100 if val_dry != 0 else 0
117
+
118
+ st.metric(label=row['model name'],
119
+ value=f"{round(val_dry, 2)}",
120
+ delta=f"-{round(loss, 1)}% Wet Loss",
121
+ delta_color="inverse")
122
+ st.write(f"**Wet Perf:** {round(val_wet, 2)}")
123
+ st.markdown("---")
124
+ else:
125
+ st.info("Please select at least one model in the sidebar.")
126
+
127
+ # --- DATA EXPORT ---
128
+ with st.expander("📂 View Raw Data & Export"):
129
+ st.dataframe(filtered_df, use_container_width=True)
130
+ csv = filtered_df.to_csv(index=False).encode('utf-8')
131
+ st.download_button("📥 Download as CSV", csv, "brake_test_report.csv", "text/csv")
132
 
133
  except Exception as e:
134
+ st.error(f"Technical Error: {e}")