IDKHowToCodeFr commited on
Commit
e581481
·
verified ·
1 Parent(s): 769b401

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. backend/main.py +7 -3
  2. frontend/pages/2_Data_Analytics.py +100 -52
backend/main.py CHANGED
@@ -103,9 +103,13 @@ def history():
103
  async def get_dataset():
104
  data_path = '/app/data/patient_dataset.csv' if os.path.exists('/app/data') else '../data/patient_dataset.csv' if os.path.exists('../data') else 'data/patient_dataset.csv'
105
  if os.path.exists(data_path):
106
- df = pd.read_csv(data_path)
107
- # Return summary or partial data to avoid huge payloads
108
- return df.to_dict(orient="records")
 
 
 
 
109
  return {"error": "Dataset not found"}
110
 
111
  @app.get("/sync")
 
103
  async def get_dataset():
104
  data_path = '/app/data/patient_dataset.csv' if os.path.exists('/app/data') else '../data/patient_dataset.csv' if os.path.exists('../data') else 'data/patient_dataset.csv'
105
  if os.path.exists(data_path):
106
+ try:
107
+ # Force UTF-8 and strip column whitespace
108
+ df = pd.read_csv(data_path, encoding='utf-8')
109
+ df.columns = [c.strip() for c in df.columns]
110
+ return df.to_dict(orient="records")
111
+ except Exception as e:
112
+ return {"error": f"Failed to read dataset: {str(e)}"}
113
  return {"error": "Dataset not found"}
114
 
115
  @app.get("/sync")
frontend/pages/2_Data_Analytics.py CHANGED
@@ -20,7 +20,12 @@ def load_data():
20
  if resp.status_code == 200:
21
  data = resp.json()
22
  if isinstance(data, list):
23
- return pd.DataFrame(data)
 
 
 
 
 
24
  st.error(f"Backend Error: {data.get('error', 'Unknown')}")
25
  except Exception as e:
26
  st.error(f"Failed to connect to backend: {e}")
@@ -42,14 +47,34 @@ else:
42
  df = full_df
43
  st.success(f"Loaded **{len(full_df):,}** patient records from backend.")
44
 
45
- # ... rest of the file stays same ...
 
 
 
 
 
 
 
 
 
 
 
 
46
  st.markdown("### 🫀 Vital Signs Distribution by Condition")
47
- vitals = ["Heart Rate (bpm)", "SpO2 Level (%)", "Systolic Blood Pressure (mmHg)", "Diastolic Blood Pressure (mmHg)", "Body Temperature (°C)"]
 
 
 
 
 
 
 
 
48
  selected_vital = st.selectbox("Select Vital Sign", vitals)
49
 
50
  fig_box = px.box(
51
- df, x="Predicted Disease", y=selected_vital,
52
- color="Predicted Disease",
53
  color_discrete_map=DISEASE_COLORS,
54
  title=f"{selected_vital} Distribution Across Conditions",
55
  template="plotly_dark",
@@ -67,44 +92,56 @@ else:
67
  c1, c2 = st.columns(2)
68
  with c1:
69
  st.markdown("##### Heart Rate vs SpO2 (Scatter Matrix)")
70
- fig_scatter = px.scatter(
71
- df, x="Heart Rate (bpm)", y="SpO2 Level (%)",
72
- color="Predicted Disease",
73
- color_discrete_map=DISEASE_COLORS,
74
- opacity=0.4, size_max=6,
75
- title="Heart Rate vs SpO2 Levels",
76
- template="plotly_dark",
77
- marginal_x="histogram",
78
- marginal_y="histogram"
79
- )
80
- fig_scatter.update_layout(
81
- paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)',
82
- height=450, legend=dict(orientation="h", yanchor="bottom", y=-0.35)
83
- )
84
- st.plotly_chart(fig_scatter, use_container_width=True)
 
 
 
 
 
 
 
85
 
86
  with c2:
87
  st.markdown("##### Temperature by Condition (Violin Plot)")
88
- fig_violin = px.violin(
89
- df, x="Predicted Disease", y="Body Temperature (°C)",
90
- color="Predicted Disease",
91
- color_discrete_map=DISEASE_COLORS,
92
- box=True, points=False,
93
- title="Body Temperature Distribution",
94
- template="plotly_dark"
95
- )
96
- fig_violin.update_layout(
97
- paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)',
98
- height=450, showlegend=False, xaxis_title="Condition", yaxis_title="Temperature (°C)"
99
- )
100
- st.plotly_chart(fig_violin, use_container_width=True)
 
 
 
 
 
101
 
102
  st.markdown("---")
103
 
104
  c3, c4 = st.columns(2)
105
  with c3:
106
  st.markdown("##### 🏥 Disease Distribution (Population Count)")
107
- counts = df["Predicted Disease"].value_counts().reset_index()
108
  counts.columns = ["Condition", "Patient Count"]
109
  fig_bar = px.bar(
110
  counts, x="Condition", y="Patient Count",
@@ -123,33 +160,44 @@ else:
123
 
124
  with c4:
125
  st.markdown("##### 🩸 Blood Pressure Density (Systolic vs Diastolic)")
126
- fig_density = px.density_heatmap(
127
- df, x="Systolic Blood Pressure (mmHg)", y="Diastolic Blood Pressure (mmHg)",
128
- color_continuous_scale="Turbo",
129
- title="Blood Pressure Population Heatmap",
130
- template="plotly_dark",
131
- nbinsx=30, nbinsy=30
132
- )
133
- fig_density.update_layout(
134
- paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)',
135
- height=420
136
- )
137
- st.plotly_chart(fig_density, use_container_width=True)
 
 
 
 
 
 
138
 
139
  st.markdown("---")
140
  st.markdown("### 📈 Patient-Specific Real-Time Monitoring")
141
- p_id = st.selectbox("Select Patient ID to view live telemetry:", df['Patient Number'].unique()[:50])
 
 
 
142
  if p_id:
143
- patient_data = df[df['Patient Number'] == p_id].iloc[0]
144
- disease = patient_data['Predicted Disease']
145
  d_color = DISEASE_COLORS.get(disease, "#636efa")
146
  st.markdown(f"**Patient Condition:** <span style='color:{d_color}; font-weight:bold'>{disease}</span>", unsafe_allow_html=True)
147
 
148
  periods = 60
149
  dates = pd.date_range(end=pd.Timestamp.now(), periods=periods, freq='25s')
150
- base_hr = patient_data['Heart Rate (bpm)']
151
- base_spo2 = patient_data['SpO2 Level (%)']
152
- base_temp = patient_data['Body Temperature (°C)']
 
 
153
  sim_hr = base_hr + np.random.normal(0, 1.2, periods).cumsum()
154
  sim_spo2 = np.clip(base_spo2 + np.random.normal(0, 0.3, periods).cumsum(), 85, 100)
155
  sim_temp = base_temp + np.random.normal(0, 0.05, periods).cumsum()
 
20
  if resp.status_code == 200:
21
  data = resp.json()
22
  if isinstance(data, list):
23
+ df = pd.DataFrame(data)
24
+ # Normalize column names: strip whitespace and ensure common naming
25
+ df.columns = [c.strip() for c in df.columns]
26
+ # Fix common encoding issues for temperature
27
+ df.columns = [c.replace('°C', '°C') for c in df.columns]
28
+ return df
29
  st.error(f"Backend Error: {data.get('error', 'Unknown')}")
30
  except Exception as e:
31
  st.error(f"Failed to connect to backend: {e}")
 
47
  df = full_df
48
  st.success(f"Loaded **{len(full_df):,}** patient records from backend.")
49
 
50
+ # ── Safety Check for Column Names ──
51
+ available_cols = df.columns.tolist()
52
+ target_x = "Predicted Disease"
53
+
54
+ if target_x not in available_cols:
55
+ # Fallback to similar name if exact match fails
56
+ matches = [c for c in available_cols if "Disease" in c or "Condition" in c]
57
+ if matches:
58
+ target_x = matches[0]
59
+ else:
60
+ st.error(f"Required column '{target_x}' missing from dataset. Found: {available_cols}")
61
+ st.stop()
62
+
63
  st.markdown("### 🫀 Vital Signs Distribution by Condition")
64
+
65
+ # Define possible vitals and filter by what's actually in the DF
66
+ vitals_all = ["Heart Rate (bpm)", "SpO2 Level (%)", "Systolic Blood Pressure (mmHg)", "Diastolic Blood Pressure (mmHg)", "Body Temperature (°C)"]
67
+ vitals = [v for v in vitals_all if v in available_cols]
68
+
69
+ if not vitals:
70
+ st.error(f"No clinical vital sign columns found in dataset. Found: {available_cols}")
71
+ st.stop()
72
+
73
  selected_vital = st.selectbox("Select Vital Sign", vitals)
74
 
75
  fig_box = px.box(
76
+ df, x=target_x, y=selected_vital,
77
+ color=target_x,
78
  color_discrete_map=DISEASE_COLORS,
79
  title=f"{selected_vital} Distribution Across Conditions",
80
  template="plotly_dark",
 
92
  c1, c2 = st.columns(2)
93
  with c1:
94
  st.markdown("##### Heart Rate vs SpO2 (Scatter Matrix)")
95
+ # Safety check for scatter columns
96
+ x_scatter = "Heart Rate (bpm)" if "Heart Rate (bpm)" in available_cols else None
97
+ y_scatter = "SpO2 Level (%)" if "SpO2 Level (%)" in available_cols else None
98
+
99
+ if x_scatter and y_scatter:
100
+ fig_scatter = px.scatter(
101
+ df, x=x_scatter, y=y_scatter,
102
+ color=target_x,
103
+ color_discrete_map=DISEASE_COLORS,
104
+ opacity=0.4, size_max=6,
105
+ title="Heart Rate vs SpO2 Levels",
106
+ template="plotly_dark",
107
+ marginal_x="histogram",
108
+ marginal_y="histogram"
109
+ )
110
+ fig_scatter.update_layout(
111
+ paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)',
112
+ height=450, legend=dict(orientation="h", yanchor="bottom", y=-0.35)
113
+ )
114
+ st.plotly_chart(fig_scatter, use_container_width=True)
115
+ else:
116
+ st.warning("Scatter plot unavailable: Required columns missing.")
117
 
118
  with c2:
119
  st.markdown("##### Temperature by Condition (Violin Plot)")
120
+ y_violin = "Body Temperature (°C)" if "Body Temperature (°C)" in available_cols else None
121
+
122
+ if y_violin:
123
+ fig_violin = px.violin(
124
+ df, x=target_x, y=y_violin,
125
+ color=target_x,
126
+ color_discrete_map=DISEASE_COLORS,
127
+ box=True, points=False,
128
+ title="Body Temperature Distribution",
129
+ template="plotly_dark"
130
+ )
131
+ fig_violin.update_layout(
132
+ paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)',
133
+ height=450, showlegend=False, xaxis_title="Condition", yaxis_title="Temperature (°C)"
134
+ )
135
+ st.plotly_chart(fig_violin, use_container_width=True)
136
+ else:
137
+ st.warning("Violin plot unavailable: Temperature column missing.")
138
 
139
  st.markdown("---")
140
 
141
  c3, c4 = st.columns(2)
142
  with c3:
143
  st.markdown("##### 🏥 Disease Distribution (Population Count)")
144
+ counts = df[target_x].value_counts().reset_index()
145
  counts.columns = ["Condition", "Patient Count"]
146
  fig_bar = px.bar(
147
  counts, x="Condition", y="Patient Count",
 
160
 
161
  with c4:
162
  st.markdown("##### 🩸 Blood Pressure Density (Systolic vs Diastolic)")
163
+ x_heat = "Systolic Blood Pressure (mmHg)" if "Systolic Blood Pressure (mmHg)" in available_cols else None
164
+ y_heat = "Diastolic Blood Pressure (mmHg)" if "Diastolic Blood Pressure (mmHg)" in available_cols else None
165
+
166
+ if x_heat and y_heat:
167
+ fig_density = px.density_heatmap(
168
+ df, x=x_heat, y=y_heat,
169
+ color_continuous_scale="Turbo",
170
+ title="Blood Pressure Population Heatmap",
171
+ template="plotly_dark",
172
+ nbinsx=30, nbinsy=30
173
+ )
174
+ fig_density.update_layout(
175
+ paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)',
176
+ height=420
177
+ )
178
+ st.plotly_chart(fig_density, use_container_width=True)
179
+ else:
180
+ st.warning("Density heatmap unavailable: Blood Pressure columns missing.")
181
 
182
  st.markdown("---")
183
  st.markdown("### 📈 Patient-Specific Real-Time Monitoring")
184
+ # Use Patient Number if available
185
+ id_col = "Patient Number" if "Patient Number" in available_cols else available_cols[0]
186
+ p_id = st.selectbox("Select Patient ID to view live telemetry:", df[id_col].unique()[:50])
187
+
188
  if p_id:
189
+ patient_data = df[df[id_col] == p_id].iloc[0]
190
+ disease = patient_data[target_x]
191
  d_color = DISEASE_COLORS.get(disease, "#636efa")
192
  st.markdown(f"**Patient Condition:** <span style='color:{d_color}; font-weight:bold'>{disease}</span>", unsafe_allow_html=True)
193
 
194
  periods = 60
195
  dates = pd.date_range(end=pd.Timestamp.now(), periods=periods, freq='25s')
196
+
197
+ # Safe access for real-time emulation
198
+ base_hr = patient_data.get('Heart Rate (bpm)', 75)
199
+ base_spo2 = patient_data.get('SpO2 Level (%)', 98)
200
+ base_temp = patient_data.get('Body Temperature (°C)', 37.0)
201
  sim_hr = base_hr + np.random.normal(0, 1.2, periods).cumsum()
202
  sim_spo2 = np.clip(base_spo2 + np.random.normal(0, 0.3, periods).cumsum(), 85, 100)
203
  sim_temp = base_temp + np.random.normal(0, 0.05, periods).cumsum()