Saicharan21 commited on
Commit
445a2e3
·
verified ·
1 Parent(s): 55fced6

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +81 -52
app.py CHANGED
@@ -106,67 +106,96 @@ def analyze_piv_csv(file):
106
  if not num_cols:
107
  return None, "No numeric columns found. Check your CSV file."
108
 
109
- fig, axes = plt.subplots(2, 2, figsize=(14, 10))
110
- fig.patch.set_facecolor("#0d1b3e")
111
- fig.suptitle("PIV Data Analysis — SJSU CardioLab MCL", color="white", fontsize=16, fontweight="bold")
112
-
113
- def style_ax(ax, title, ylabel):
114
- ax.set_facecolor("#1a2744")
115
- ax.set_title(title, color="white", fontweight="bold")
116
- ax.set_ylabel(ylabel, color="#a8b2d8")
117
- ax.tick_params(colors="#a8b2d8")
118
- ax.grid(True, alpha=0.2, color="#2d4a8a")
 
 
 
 
119
  for spine in ["top","right"]: ax.spines[spine].set_visible(False)
120
  for spine in ["bottom","left"]: ax.spines[spine].set_color("#2d4a8a")
121
 
122
- x = range(len(df))
123
- vel_col = next((c for c in cols if any(k in c for k in ["vel","speed","u","v_mag"])), num_cols[0] if num_cols else None)
 
124
  shear_col = next((c for c in cols if any(k in c for k in ["shear","stress","tau","wss"])), num_cols[1] if len(num_cols)>1 else None)
 
 
125
 
126
- # Plot 1 - Velocity
127
- ax1 = axes[0,0]
128
  if vel_col:
129
- ax1.plot(df[vel_col], color="#e63946", linewidth=2.5, marker="o", markersize=4)
130
- ax1.axhline(y=2.0, color="#ffd700", linestyle="--", linewidth=1.5, label="Risk (2.0 m/s)")
131
- ax1.fill_between(x, df[vel_col], alpha=0.2, color="#e63946")
132
- ax1.legend(fontsize=8, labelcolor="white", facecolor="#1a2744")
133
- style_ax(ax1, "Velocity Profile", "Velocity (m/s)")
134
-
135
- # Plot 2 - Shear
136
- ax2 = axes[0,1]
 
 
 
 
 
 
 
137
  if shear_col:
138
- ax2.plot(df[shear_col], color="#4361ee", linewidth=2.5, marker="s", markersize=4)
139
- ax2.axhline(y=5, color="#ffd700", linestyle="--", linewidth=1.5, label="Caution (5 Pa)")
140
- ax2.axhline(y=10, color="#e63946", linestyle="--", linewidth=1.5, label="High risk (10 Pa)")
141
- ax2.fill_between(x, df[shear_col], alpha=0.2, color="#4361ee")
142
- ax2.legend(fontsize=8, labelcolor="white", facecolor="#1a2744")
143
- elif len(num_cols)>1:
144
- ax2.plot(df[num_cols[1]], color="#4361ee", linewidth=2.5)
145
- style_ax(ax2, "Shear Stress", "Shear Stress (Pa)")
146
-
147
- # Plot 3 - Distribution
148
- ax3 = axes[1,0]
149
- if vel_col:
150
- ax3.hist(df[vel_col].dropna(), bins=20, color="#2ecc71", alpha=0.8, edgecolor="#0d1b3e")
151
- style_ax(ax3, "Velocity Distribution", "Count")
152
- ax3.set_xlabel("Value", color="#a8b2d8")
153
-
154
- # Plot 4 - Stats
155
- ax4 = axes[1,1]
156
- ax4.set_facecolor("#1a2744")
 
 
 
 
 
 
157
  ax4.axis("off")
158
- stats = ""
159
  risk = []
160
- for col in num_cols[:3]:
161
- mn = df[col].mean()
162
- mx = df[col].max()
163
- stats += col[:12]+":"+chr(10)+" Mean: "+str(round(mn,3))+chr(10)+" Max: "+str(round(mx,3))+chr(10)+chr(10)
164
- if "vel" in col and mx > 2.0: risk.append("HIGH VELOCITY: stenosis risk")
165
- if "shear" in col and mx > 10: risk.append("HIGH SHEAR: thrombosis risk")
166
- if risk: stats += "RISK FLAGS:"+chr(10)+" "+chr(10)+" ".join(risk)
167
- ax4.text(0.05, 0.95, "SUMMARY STATS"+chr(10)+"━"*18+chr(10)+stats, transform=ax4.transAxes,
168
- color="white", fontsize=9, va="top", fontfamily="monospace",
169
- bbox=dict(boxstyle="round", facecolor="#0d1b3e", edgecolor="#4361ee"))
 
 
 
 
 
 
 
 
 
 
170
 
171
  plt.tight_layout()
172
  buf = io.BytesIO()
 
106
  if not num_cols:
107
  return None, "No numeric columns found. Check your CSV file."
108
 
109
+ fig = plt.figure(figsize=(16, 11))
110
+ fig.patch.set_facecolor("#0a1628")
111
+ fig.suptitle("PIV Data Analysis — SJSU CardioLab MCL", color="white", fontsize=18, fontweight="bold", y=0.98)
112
+
113
+ gs = fig.add_gridspec(2, 2, hspace=0.38, wspace=0.32, left=0.08, right=0.97, top=0.93, bottom=0.08)
114
+ axes = [fig.add_subplot(gs[0,0]), fig.add_subplot(gs[0,1]), fig.add_subplot(gs[1,0]), fig.add_subplot(gs[1,1])]
115
+
116
+ def style_ax(ax, title, xlabel, ylabel):
117
+ ax.set_facecolor("#132340")
118
+ ax.set_title(title, color="white", fontweight="bold", fontsize=13, pad=10)
119
+ ax.set_xlabel(xlabel, color="#7eb8f7", fontsize=11)
120
+ ax.set_ylabel(ylabel, color="#7eb8f7", fontsize=11)
121
+ ax.tick_params(colors="#a8b2d8", labelsize=10)
122
+ ax.grid(True, alpha=0.25, color="#2d4a8a", linestyle="--")
123
  for spine in ["top","right"]: ax.spines[spine].set_visible(False)
124
  for spine in ["bottom","left"]: ax.spines[spine].set_color("#2d4a8a")
125
 
126
+ x = np.arange(len(df))
127
+ time_col = next((c for c in cols if "time" in c or "frame" in c or "x" == c), None)
128
+ vel_col = next((c for c in cols if any(k in c for k in ["vel","speed","v_mag","magnitude"])), num_cols[0] if num_cols else None)
129
  shear_col = next((c for c in cols if any(k in c for k in ["shear","stress","tau","wss"])), num_cols[1] if len(num_cols)>1 else None)
130
+ x_vals = df[time_col] if time_col else x
131
+ x_label = time_col.title() if time_col else "Sample Index"
132
 
133
+ # Plot 1 - Velocity profile - large filled area chart
134
+ ax1 = axes[0]
135
  if vel_col:
136
+ v_data = df[vel_col].values
137
+ ax1.fill_between(x_vals, v_data, alpha=0.25, color="#e63946")
138
+ ax1.plot(x_vals, v_data, color="#e63946", linewidth=3, marker="o", markersize=5, label="Velocity")
139
+ ax1.axhline(y=2.0, color="#ffd700", linestyle="--", linewidth=2, label="Risk threshold: 2.0 m/s")
140
+ max_v = v_data.max()
141
+ max_i = v_data.argmax()
142
+ ax1.annotate(f"Peak: {max_v:.2f} m/s", xy=(x_vals.iloc[max_i] if time_col else max_i, max_v),
143
+ xytext=(10, 10), textcoords="offset points", color="#ffd700", fontsize=10, fontweight="bold",
144
+ arrowprops=dict(arrowstyle="->", color="#ffd700", lw=1.5))
145
+ ax1.legend(fontsize=10, labelcolor="white", facecolor="#132340", framealpha=0.8)
146
+ ax1.set_ylim(bottom=0)
147
+ style_ax(ax1, "Velocity Profile", x_label, "Velocity (m/s)")
148
+
149
+ # Plot 2 - Shear stress with risk zones
150
+ ax2 = axes[1]
151
  if shear_col:
152
+ s_data = df[shear_col].values
153
+ x_plot = x_vals.values if time_col else x
154
+ ax2.fill_between(x_plot, s_data, alpha=0.25, color="#4361ee")
155
+ ax2.fill_between(x_plot, s_data, 10, where=s_data>10, alpha=0.4, color="#e63946", label="High risk zone")
156
+ ax2.fill_between(x_plot, s_data, 5, where=(s_data>5)&(s_data<=10), alpha=0.3, color="#ffd700", label="Caution zone")
157
+ ax2.plot(x_plot, s_data, color="#4361ee", linewidth=3, marker="s", markersize=5)
158
+ ax2.axhline(y=5, color="#ffd700", linestyle="--", linewidth=2, label="Caution: 5 Pa")
159
+ ax2.axhline(y=10, color="#e63946", linestyle="--", linewidth=2, label="High risk: 10 Pa")
160
+ ax2.legend(fontsize=9, labelcolor="white", facecolor="#132340", framealpha=0.8)
161
+ ax2.set_ylim(bottom=0)
162
+ style_ax(ax2, "Wall Shear Stress", x_label, "Shear Stress (Pa)")
163
+
164
+ # Plot 3 - Velocity vs Shear scatter plot
165
+ ax3 = axes[2]
166
+ if vel_col and shear_col:
167
+ sc = ax3.scatter(df[vel_col], df[shear_col], c=x, cmap="RdYlGn_r", s=80, edgecolors="white", linewidth=0.5, zorder=5)
168
+ plt.colorbar(sc, ax=ax3, label="Time progression").ax.yaxis.label.set_color("white")
169
+ ax3.axvline(x=2.0, color="#ffd700", linestyle="--", linewidth=2, label="Vel. risk: 2.0")
170
+ ax3.axhline(y=10, color="#e63946", linestyle="--", linewidth=2, label="Shear risk: 10")
171
+ ax3.legend(fontsize=9, labelcolor="white", facecolor="#132340", framealpha=0.8)
172
+ style_ax(ax3, "Velocity vs Shear Stress", "Velocity (m/s)", "Shear Stress (Pa)")
173
+
174
+ # Plot 4 - Clinical summary dashboard
175
+ ax4 = axes[3]
176
+ ax4.set_facecolor("#0d1b3e")
177
  ax4.axis("off")
 
178
  risk = []
179
+ summary = "CLINICAL SUMMARY"+chr(10)+"━"*24+chr(10)+chr(10)
180
+ for col in num_cols[:4]:
181
+ mn = round(df[col].mean(),3)
182
+ mx = round(df[col].max(),3)
183
+ mn_v = round(df[col].min(),3)
184
+ summary += f"{col[:14]:14s}"+chr(10)+f" Mean: {mn:8.3f}"+chr(10)+f" Max: {mx:8.3f}"+chr(10)+f" Min: {mn_v:8.3f}"+chr(10)+chr(10)
185
+ if "vel" in col and mx > 2.0: risk.append("HIGH VELOCITY (>2.0 m/s)")
186
+ if "shear" in col and mx > 10: risk.append("HIGH SHEAR (>10 Pa)")
187
+ summary += ""*24+chr(10)
188
+ if risk:
189
+ summary += "RISK FLAGS DETECTED:"+chr(10)
190
+ for r in risk: summary += " ⚠ "+r+chr(10)
191
+ overall = "HIGH RISK — Clinical review needed"
192
+ else:
193
+ summary += "STATUS: All values normal"+chr(10)
194
+ overall = "LOW RISK — Continue monitoring"
195
+ summary += chr(10)+"OVERALL: "+overall
196
+ ax4.text(0.05, 0.97, summary, transform=ax4.transAxes, color="white", fontsize=10,
197
+ va="top", fontfamily="monospace",
198
+ bbox=dict(boxstyle="round,pad=0.8", facecolor="#132340", edgecolor="#e63946" if risk else "#2ecc71", linewidth=2))
199
 
200
  plt.tight_layout()
201
  buf = io.BytesIO()