UCS2014 commited on
Commit
ee9900b
·
verified ·
1 Parent(s): 42fab84

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +38 -23
app.py CHANGED
@@ -93,7 +93,7 @@ div[data-testid="stExpander"] div[data-baseweb="tab-list"] {
93
  </style>
94
  """, unsafe_allow_html=True)
95
 
96
- # Center text in all pandas Styler tables (headers + cells)
97
  TABLE_CENTER_CSS = [
98
  dict(selector="th", props=[("text-align", "center")]),
99
  dict(selector="td", props=[("text-align", "center")]),
@@ -162,7 +162,7 @@ def rmse(y_true, y_pred) -> float:
162
  def pearson_r(y_true, y_pred) -> float:
163
  a = np.asarray(y_true, dtype=float)
164
  p = np.asarray(y_pred, dtype=float)
165
- if a.size < 2:
166
  return float("nan")
167
  return float(np.corrcoef(a, p)[0, 1])
168
 
@@ -230,7 +230,7 @@ def _excel_safe_name(name: str) -> str:
230
  safe = ''.join('_' if ch in bad else ch for ch in str(name))
231
  return safe[:31]
232
 
233
- def _round_numeric(df: pd.DataFrame, ndigits: int = 2) -> pd.DataFrame:
234
  out = df.copy()
235
  for c in out.columns:
236
  if pd.api.types.is_float_dtype(out[c]) or pd.api.types.is_integer_dtype(out[c]):
@@ -267,7 +267,7 @@ def _excel_autofit(writer, sheet_name: str, df: pd.DataFrame, min_w: int = 8, ma
267
  ws.set_column(i, i, max(min_w, min(max_len + 2, max_w)))
268
  ws.freeze_panes(1, 0)
269
 
270
- def _add_sheet(sheets: dict, order: list, name: str, df: pd.DataFrame, ndigits: int):
271
  if isinstance(df, pd.DataFrame) and not df.empty:
272
  sheets[name] = _round_numeric(df, ndigits)
273
  order.append(name)
@@ -283,7 +283,8 @@ def _available_sections():
283
  sections += ["Info"]
284
  return sections
285
 
286
- def build_export_workbook(selected: list[str], ndigits: int = 2) -> tuple[bytes|None, str|None, list[str]]:
 
287
  res = st.session_state.get("results", {})
288
  if not res:
289
  return None, None, []
@@ -358,11 +359,11 @@ def build_export_workbook(selected: list[str], ndigits: int = 2) -> tuple[bytes|
358
  fname = f"YM_Export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
359
  return bio.getvalue(), fname, order
360
 
361
- def render_export_button(key: str = "export_main") -> None:
 
362
  st.divider()
363
  st.markdown("### Export to Excel")
364
 
365
- default_sections = _available_sections()
366
  all_sections = [
367
  "Training","Training_Metrics","Training_Summary",
368
  "Testing","Testing_Metrics","Testing_Summary",
@@ -370,14 +371,17 @@ def render_export_button(key: str = "export_main") -> None:
370
  "Prediction","Prediction_Summary",
371
  "Training_Ranges","Info"
372
  ]
373
- selected = st.multiselect("Sheets to include", options=all_sections, default=default_sections)
374
- c1, c2 = st.columns([1,2])
375
- with c1:
376
- ndigits = st.number_input("Rounding (decimals)", 0, 6, 2, 1)
377
- with c2:
378
- base_name = st.text_input("Base filename", value="YM_Export")
379
-
380
- data, _, names = build_export_workbook(selected=selected, ndigits=int(ndigits))
 
 
 
381
  if names:
382
  st.caption("Will include: " + ", ".join(names))
383
 
@@ -387,7 +391,7 @@ def render_export_button(key: str = "export_main") -> None:
387
  file_name=((base_name or "YM_Export") + "_" + datetime.now().strftime("%Y%m%d_%H%M%S") + ".xlsx") if data else "YM_Export.xlsx",
388
  mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
389
  disabled=(data is None),
390
- key=key,
391
  )
392
 
393
  # =========================
@@ -510,7 +514,7 @@ def preview_tracks(df: pd.DataFrame, cols: list[str]):
510
  ax.text(0.5,0.5,"No selected columns",ha="center",va="center"); ax.axis("off")
511
  return fig
512
  fig, axes = plt.subplots(1, n, figsize=(2.2*n, 7.0), sharey=True, dpi=100)
513
- if n == 1:
514
  axes = [axes]
515
  idx = np.arange(1, len(df) + 1)
516
  for ax, col in zip(axes, cols):
@@ -744,6 +748,10 @@ if st.session_state.app_step == "dev":
744
  st.session_state.train_ranges = {f:(float(tr_min[f]), float(tr_max[f])) for f in FEATURES}
745
  st.markdown('<div class="st-message-box st-success">Case has been built and results are displayed below.</div>', unsafe_allow_html=True)
746
 
 
 
 
 
747
  def _dev_block(df, m):
748
  c1,c2,c3 = st.columns(3)
749
  c1.metric("R", f"{m['R']:.2f}")
@@ -826,6 +834,13 @@ if st.session_state.app_step == "validate":
826
  st.session_state.results["sv_val"]={"n":len(df), "pred_min":float(df[PRED_COL].min()), "pred_max":float(df[PRED_COL].max()), "oor":oor_pct}
827
  st.session_state.results["oor_tbl"]=tbl
828
 
 
 
 
 
 
 
 
829
  if "Validate" in st.session_state.results:
830
  m = st.session_state.results["m_val"]
831
  c1,c2,c3 = st.columns(3)
@@ -902,6 +917,10 @@ if st.session_state.app_step == "predict":
902
  "oor":oor_pct
903
  }
904
 
 
 
 
 
905
  if "PredictOnly" in st.session_state.results:
906
  df = st.session_state.results["PredictOnly"]; sv = st.session_state.results["sv_pred"]
907
 
@@ -962,11 +981,7 @@ if st.session_state.show_preview_modal:
962
  df_centered_rounded(tbl)
963
  st.session_state.show_preview_modal = False
964
 
965
- # === Bottom-of-page Export (per step) =========================================
966
- if st.session_state.app_step in ("dev", "validate", "predict"):
967
- has_results = any(k in st.session_state.results for k in ("Train", "Test", "Validate", "PredictOnly"))
968
- if has_results:
969
- render_export_button(key=f"export_{st.session_state.app_step}")
970
 
971
  # =========================
972
  # Footer
@@ -978,4 +993,4 @@ st.markdown("""
978
  © 2025 Smart Thinking AI-Solutions Team. All rights reserved.<br>
979
  Website: <a href="https://smartthinking.com.sa" target="_blank" rel="noopener noreferrer">smartthinking.com.sa</a>
980
  </div>
981
- """, unsafe_allow_html=True)
 
93
  </style>
94
  """, unsafe_allow_html=True)
95
 
96
+ # Center text in pandas tables
97
  TABLE_CENTER_CSS = [
98
  dict(selector="th", props=[("text-align", "center")]),
99
  dict(selector="td", props=[("text-align", "center")]),
 
162
  def pearson_r(y_true, y_pred) -> float:
163
  a = np.asarray(y_true, dtype=float)
164
  p = np.asarray(y_pred, dtype=float)
165
+ if a.size < 2:
166
  return float("nan")
167
  return float(np.corrcoef(a, p)[0, 1])
168
 
 
230
  safe = ''.join('_' if ch in bad else ch for ch in str(name))
231
  return safe[:31]
232
 
233
+ def _round_numeric(df: pd.DataFrame, ndigits: int = 3) -> pd.DataFrame:
234
  out = df.copy()
235
  for c in out.columns:
236
  if pd.api.types.is_float_dtype(out[c]) or pd.api.types.is_integer_dtype(out[c]):
 
267
  ws.set_column(i, i, max(min_w, min(max_len + 2, max_w)))
268
  ws.freeze_panes(1, 0)
269
 
270
+ def _add_sheet(sheets: dict, order: list, name: str, df: pd.DataFrame, ndigits: int = 3):
271
  if isinstance(df, pd.DataFrame) and not df.empty:
272
  sheets[name] = _round_numeric(df, ndigits)
273
  order.append(name)
 
283
  sections += ["Info"]
284
  return sections
285
 
286
+ def build_export_workbook(selected: list[str], ndigits: int = 3) -> tuple[bytes|None, str|None, list[str]]:
287
+ """Builds an in-memory Excel workbook for selected sheets; fixed rounding to 3 decimals."""
288
  res = st.session_state.get("results", {})
289
  if not res:
290
  return None, None, []
 
359
  fname = f"YM_Export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
360
  return bio.getvalue(), fname, order
361
 
362
+ def render_export_button(phase_key: str, default_sections: list[str]) -> None:
363
+ """Export UI — dropdown checklist, fixed rounding=3, appears inside each phase after results."""
364
  st.divider()
365
  st.markdown("### Export to Excel")
366
 
 
367
  all_sections = [
368
  "Training","Training_Metrics","Training_Summary",
369
  "Testing","Testing_Metrics","Testing_Summary",
 
371
  "Prediction","Prediction_Summary",
372
  "Training_Ranges","Info"
373
  ]
374
+ # Dropdown checklist
375
+ selected = st.multiselect(
376
+ "Sheets to include",
377
+ options=all_sections,
378
+ default=default_sections,
379
+ help="Choose which sheets to include in the Excel export.",
380
+ )
381
+
382
+ base_name = st.text_input("Base filename", value="YM_Export", key=f"basename_{phase_key}")
383
+
384
+ data, _, names = build_export_workbook(selected=selected, ndigits=3) # fixed 3 decimals
385
  if names:
386
  st.caption("Will include: " + ", ".join(names))
387
 
 
391
  file_name=((base_name or "YM_Export") + "_" + datetime.now().strftime("%Y%m%d_%H%M%S") + ".xlsx") if data else "YM_Export.xlsx",
392
  mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
393
  disabled=(data is None),
394
+ key=f"download_{phase_key}",
395
  )
396
 
397
  # =========================
 
514
  ax.text(0.5,0.5,"No selected columns",ha="center",va="center"); ax.axis("off")
515
  return fig
516
  fig, axes = plt.subplots(1, n, figsize=(2.2*n, 7.0), sharey=True, dpi=100)
517
+ if n == 1:
518
  axes = [axes]
519
  idx = np.arange(1, len(df) + 1)
520
  for ax, col in zip(axes, cols):
 
748
  st.session_state.train_ranges = {f:(float(tr_min[f]), float(tr_max[f])) for f in FEATURES}
749
  st.markdown('<div class="st-message-box st-success">Case has been built and results are displayed below.</div>', unsafe_allow_html=True)
750
 
751
+ # --- Export (DEV phase) ---
752
+ default_sections = [s for s in _available_sections() if s.startswith("Training") or s.startswith("Testing")] + ["Training_Ranges","Info"]
753
+ render_export_button(phase_key="dev", default_sections=default_sections)
754
+
755
  def _dev_block(df, m):
756
  c1,c2,c3 = st.columns(3)
757
  c1.metric("R", f"{m['R']:.2f}")
 
834
  st.session_state.results["sv_val"]={"n":len(df), "pred_min":float(df[PRED_COL].min()), "pred_max":float(df[PRED_COL].max()), "oor":oor_pct}
835
  st.session_state.results["oor_tbl"]=tbl
836
 
837
+ # --- Export (VALIDATE phase) ---
838
+ default_sections = ["Validation","Validation_Metrics","Validation_Summary"]
839
+ if st.session_state.results.get("oor_tbl") is not None and not st.session_state.results["oor_tbl"].empty:
840
+ default_sections.append("Validation_OOR")
841
+ default_sections += ["Training_Ranges","Info"]
842
+ render_export_button(phase_key="validate", default_sections=default_sections)
843
+
844
  if "Validate" in st.session_state.results:
845
  m = st.session_state.results["m_val"]
846
  c1,c2,c3 = st.columns(3)
 
917
  "oor":oor_pct
918
  }
919
 
920
+ # --- Export (PREDICT phase) ---
921
+ default_sections = ["Prediction","Prediction_Summary","Training_Ranges","Info"]
922
+ render_export_button(phase_key="predict", default_sections=default_sections)
923
+
924
  if "PredictOnly" in st.session_state.results:
925
  df = st.session_state.results["PredictOnly"]; sv = st.session_state.results["sv_pred"]
926
 
 
981
  df_centered_rounded(tbl)
982
  st.session_state.show_preview_modal = False
983
 
984
+ # (Removed the old global bottom-of-page export — now shown per phase)
 
 
 
 
985
 
986
  # =========================
987
  # Footer
 
993
  © 2025 Smart Thinking AI-Solutions Team. All rights reserved.<br>
994
  Website: <a href="https://smartthinking.com.sa" target="_blank" rel="noopener noreferrer">smartthinking.com.sa</a>
995
  </div>
996
+ """, unsafe_allow_html=True)