UCS2014 commited on
Commit
7aae2b0
·
verified ·
1 Parent(s): c08ab06

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -55
app.py CHANGED
@@ -15,21 +15,20 @@ import plotly.graph_objects as go
15
  from sklearn.metrics import mean_squared_error, mean_absolute_error
16
 
17
  # =========================
18
- # Constants (simple & robust)
19
  # =========================
20
  FEATURES = ["Q, gpm", "SPP(psi)", "T (kft.lbf)", "WOB (klbf)", "ROP (ft/h)"]
21
  TARGET = "UCS"
22
  MODELS_DIR = Path("models")
23
  DEFAULT_MODEL = MODELS_DIR / "ucs_rf.joblib"
24
  MODEL_FALLBACKS = [MODELS_DIR / "model.joblib", MODELS_DIR / "model.pkl"]
25
-
26
  COLORS = {"pred": "#1f77b4", "actual": "#f2b702", "ref": "#5a5a5a"}
27
 
28
  # ---- Plot sizing controls (edit here) ----
29
- CROSS_W = 500; CROSS_H = 500 # square cross-plot (Build + Validate)
30
  TRACK_W = 400; TRACK_H = 950 # log-strip style (all pages)
31
  FONT_SZ = 13
32
- PLOT_COLS = [14, 0.5, 10] # 3-column band: left • spacer • right (Build + Validate)
33
  CROSS_NUDGE = 0.5 # inner columns [CROSS_NUDGE : 1] → bigger = more right
34
 
35
  # =========================
@@ -38,27 +37,38 @@ CROSS_NUDGE = 0.5 # inner columns [CROSS_NUDGE : 1] → bigger =
38
  st.set_page_config(page_title="ST_GeoMech_UCS", page_icon="logo.png", layout="wide")
39
  st.markdown("<style>header, footer{visibility:hidden !important;}</style>", unsafe_allow_html=True)
40
 
41
- # Hide drag-n-drop helper texts inside uploaders; keep the Browse button
42
  st.markdown(
43
  """
44
  <style>
45
  .stApp { background:#fff; }
46
  section[data-testid="stSidebar"] { background:#F6F9FC; }
47
  .block-container { padding-top:.5rem; padding-bottom:.5rem; }
 
 
48
  .stButton>button { background:#007bff; color:#fff; font-weight:600; border-radius:8px; border:none; }
49
  .stButton>button:hover { background:#0056b3; }
 
 
50
  .st-hero { display:flex; align-items:center; gap:16px; padding-top:4px; }
51
  .st-hero .brand { width:110px; height:110px; object-fit:contain; }
52
  .st-hero h1 { margin:0; line-height:1.05; }
53
  .st-hero .tagline { margin:2px 0 0 2px; color:#6b7280; font-size:1.05rem; font-style:italic; }
 
54
  [data-testid="stBlock"]{ margin-top:0 !important; }
55
 
56
- /* Remove drag & drop copy and limit line in uploader */
 
57
  [data-testid="stFileUploadDropzone"] [data-testid="stFileUploaderInstructions"],
58
- [data-testid="stFileUploadDropzone"] [data-testid="stCaptionContainer"],
59
- .stFileUploader .dz-message {display:none !important;}
 
60
 
61
- /* Center our HTML tables */
 
 
 
 
 
62
  .table-center table { margin-left:auto; margin-right:auto; border-collapse:collapse; }
63
  .table-center table th, .table-center table td {
64
  text-align:center !important; padding:6px 10px; border:1px solid #e5e7eb;
@@ -70,7 +80,7 @@ st.markdown(
70
  )
71
 
72
  # =========================
73
- # Password gate (define first, then call)
74
  # =========================
75
  def inline_logo(path="logo.png") -> str:
76
  try:
@@ -137,29 +147,15 @@ add_password_gate()
137
  # =========================
138
  # Utilities
139
  # =========================
140
- try:
141
- dialog = st.dialog
142
- except AttributeError:
143
- def dialog(title):
144
- def deco(fn):
145
- def wrapper(*args, **kwargs):
146
- with st.expander(title, expanded=True):
147
- return fn(*args, **kwargs)
148
- return wrapper
149
- return deco
150
-
151
  def rmse(y_true, y_pred) -> float:
152
  return float(np.sqrt(mean_squared_error(y_true, y_pred)))
153
 
154
  def corrcoef_safe(y_true, y_pred) -> float:
155
  a = pd.Series(y_true, dtype=float)
156
  b = pd.Series(y_pred, dtype=float)
157
- a = a.replace([np.inf, -np.inf], np.nan).dropna()
158
- b = b.replace([np.inf, -np.inf], np.nan).dropna()
159
- n = min(len(a), len(b))
160
- if n == 0:
161
- return float("nan")
162
- return float(np.corrcoef(a.iloc[:n], b.iloc[:n])[0, 1])
163
 
164
  @st.cache_resource(show_spinner=False)
165
  def load_model(model_path: str):
@@ -236,7 +232,6 @@ def cross_plot(actual, pred):
236
  margin=dict(l=64, r=18, t=10, b=48), hovermode="closest",
237
  font=dict(size=FONT_SZ)
238
  )
239
- # identical x & y ranges/ticks; stays locked on zoom
240
  axis_common = dict(
241
  range=[lo, hi], ticks="outside", tickformat=",.0f",
242
  tick0=tick0, dtick=step,
@@ -254,14 +249,13 @@ def track_plot(df, include_actual=True):
254
  y = pd.Series(df[depth_col]).astype(float)
255
  ylab = depth_col
256
  y_min, y_max = float(y.min()), float(y.max())
257
- y_range = [y_max, y_min] # reversed for log profile style
258
  else:
259
  y = pd.Series(np.arange(1, len(df) + 1))
260
  ylab = "Point Index"
261
  y_min, y_max = float(y.min()), float(y.max())
262
  y_range = [y_max, y_min]
263
 
264
- # X (UCS) range & ticks
265
  x_series = pd.Series(df.get("UCS_Pred", pd.Series(dtype=float))).astype(float)
266
  if include_actual and TARGET in df.columns:
267
  x_series = pd.concat([x_series, pd.Series(df[TARGET]).astype(float)], ignore_index=True)
@@ -318,8 +312,7 @@ def preview_tracks(df: pd.DataFrame, cols: list[str]):
318
  if n == 0:
319
  fig, ax = plt.subplots(figsize=(4, 2))
320
  ax.text(0.5,0.5,"No selected columns",ha="center",va="center")
321
- ax.axis("off")
322
- return fig
323
  fig, axes = plt.subplots(1, n, figsize=(2.2*n, 7.0), sharey=True, dpi=100)
324
  if n == 1: axes = [axes]
325
  idx = np.arange(1, len(df) + 1)
@@ -360,7 +353,7 @@ def preview_modal(book: dict[str, pd.DataFrame]):
360
  html_table_center(tbl, index=False)
361
 
362
  # =========================
363
- # Load model (simple)
364
  # =========================
365
  def ensure_model() -> Path|None:
366
  for p in [DEFAULT_MODEL, *MODEL_FALLBACKS]:
@@ -456,6 +449,17 @@ if st.session_state.app_step == "dev":
456
  df0 = next(iter(tmp.values()))
457
  st.sidebar.caption(f"**Data loaded:** {st.session_state.dev_file_name} • {df0.shape[0]} rows × {df0.shape[1]} cols")
458
 
 
 
 
 
 
 
 
 
 
 
 
459
  # Preview button ALWAYS enabled
460
  if st.sidebar.button("Preview data", use_container_width=True):
461
  if not st.session_state.dev_file_loaded:
@@ -468,17 +472,6 @@ if st.session_state.app_step == "dev":
468
  if st.sidebar.button("Proceed to Validation â–¶", use_container_width=True): st.session_state.app_step="validate"; st.rerun()
469
  if st.sidebar.button("Proceed to Prediction â–¶", use_container_width=True): st.session_state.app_step="predict"; st.rerun()
470
 
471
- # ---- Pinned helper at the very top of the page ----
472
- helper_top = st.container()
473
- with helper_top:
474
- st.subheader("Case Building")
475
- if st.session_state.dev_file_loaded and st.session_state.dev_preview:
476
- st.info("Previewed ✓ — now click **Run Model**.")
477
- elif st.session_state.dev_file_loaded:
478
- st.info("📄 **Preview uploaded data** using the sidebar button, then click **Run Model**.")
479
- else:
480
- st.write("**Upload your data to build a case, then run the model to review development performance.**")
481
-
482
  if run and st.session_state.dev_file_bytes:
483
  book = read_book_bytes(st.session_state.dev_file_bytes)
484
  sh_train = find_sheet(book, ["Train","Training","training2","train","training"])
@@ -513,7 +506,7 @@ if st.session_state.app_step == "dev":
513
  c1.metric("R", f"{m['R']:.4f}"); c2.metric("RMSE", f"{m['RMSE']:.4f}"); c3.metric("MAE", f"{m['MAE']:.4f}")
514
  left, spacer, right = st.columns(PLOT_COLS)
515
  with left:
516
- pad, plotcol = left.columns([CROSS_NUDGE, 1]) # shift cross-plot right inside its band
517
  with plotcol:
518
  st.plotly_chart(cross_plot(df[TARGET], df["UCS_Pred"]),
519
  use_container_width=False, config={"displayModeBar": False, "scrollZoom": True})
@@ -540,20 +533,21 @@ if st.session_state.app_step == "validate":
540
  df0 = next(iter(book.values()))
541
  st.sidebar.caption(f"**Data loaded:** {up.name} • {df0.shape[0]} rows × {df0.shape[1]} cols")
542
 
 
 
 
 
 
 
543
  if st.sidebar.button("Preview data", use_container_width=True):
544
  if up is None:
545
  st.warning("Upload an Excel file first, then preview.")
546
  else:
547
  preview_modal(read_book_bytes(up.getvalue()))
548
-
549
  go_btn = st.sidebar.button("Predict", type="primary", use_container_width=True)
550
  if st.sidebar.button("⬅ Back to Case Building", use_container_width=True): st.session_state.app_step="dev"; st.rerun()
551
  if st.sidebar.button("Proceed to Prediction â–¶", use_container_width=True): st.session_state.app_step="predict"; st.rerun()
552
 
553
- # pinned
554
- st.subheader("Validate the Model")
555
- st.write("Upload a dataset with the same **features** and **UCS** to evaluate performance.")
556
-
557
  if go_btn and up is not None:
558
  book = read_book_bytes(up.getvalue())
559
  name = find_sheet(book, ["Validation","Validate","validation2","Val","val"]) or list(book.keys())[0]
@@ -616,19 +610,20 @@ if st.session_state.app_step == "predict":
616
  df0 = next(iter(book.values()))
617
  st.sidebar.caption(f"**Data loaded:** {up.name} • {df0.shape[0]} rows × {df0.shape[1]} cols")
618
 
 
 
 
 
 
 
619
  if st.sidebar.button("Preview data", use_container_width=True):
620
  if up is None:
621
  st.warning("Upload an Excel file first, then preview.")
622
  else:
623
  preview_modal(read_book_bytes(up.getvalue()))
624
-
625
  go_btn = st.sidebar.button("Predict", type="primary", use_container_width=True)
626
  if st.sidebar.button("⬅ Back to Case Building", use_container_width=True): st.session_state.app_step="dev"; st.rerun()
627
 
628
- # pinned
629
- st.subheader("Prediction")
630
- st.write("Upload a dataset with the feature columns (no **UCS**).")
631
-
632
  if go_btn and up is not None:
633
  book = read_book_bytes(up.getvalue()); name = list(book.keys())[0]
634
  df = book[name].copy()
 
15
  from sklearn.metrics import mean_squared_error, mean_absolute_error
16
 
17
  # =========================
18
+ # Constants
19
  # =========================
20
  FEATURES = ["Q, gpm", "SPP(psi)", "T (kft.lbf)", "WOB (klbf)", "ROP (ft/h)"]
21
  TARGET = "UCS"
22
  MODELS_DIR = Path("models")
23
  DEFAULT_MODEL = MODELS_DIR / "ucs_rf.joblib"
24
  MODEL_FALLBACKS = [MODELS_DIR / "model.joblib", MODELS_DIR / "model.pkl"]
 
25
  COLORS = {"pred": "#1f77b4", "actual": "#f2b702", "ref": "#5a5a5a"}
26
 
27
  # ---- Plot sizing controls (edit here) ----
28
+ CROSS_W = 420; CROSS_H = 420 # square cross-plot (original look)
29
  TRACK_W = 400; TRACK_H = 950 # log-strip style (all pages)
30
  FONT_SZ = 13
31
+ PLOT_COLS = [14, 0.5, 10] # 3-column band: left • spacer • right
32
  CROSS_NUDGE = 0.5 # inner columns [CROSS_NUDGE : 1] → bigger = more right
33
 
34
  # =========================
 
37
  st.set_page_config(page_title="ST_GeoMech_UCS", page_icon="logo.png", layout="wide")
38
  st.markdown("<style>header, footer{visibility:hidden !important;}</style>", unsafe_allow_html=True)
39
 
 
40
  st.markdown(
41
  """
42
  <style>
43
  .stApp { background:#fff; }
44
  section[data-testid="stSidebar"] { background:#F6F9FC; }
45
  .block-container { padding-top:.5rem; padding-bottom:.5rem; }
46
+
47
+ /* Buttons look */
48
  .stButton>button { background:#007bff; color:#fff; font-weight:600; border-radius:8px; border:none; }
49
  .stButton>button:hover { background:#0056b3; }
50
+
51
+ /* Brand header */
52
  .st-hero { display:flex; align-items:center; gap:16px; padding-top:4px; }
53
  .st-hero .brand { width:110px; height:110px; object-fit:contain; }
54
  .st-hero h1 { margin:0; line-height:1.05; }
55
  .st-hero .tagline { margin:2px 0 0 2px; color:#6b7280; font-size:1.05rem; font-style:italic; }
56
+
57
  [data-testid="stBlock"]{ margin-top:0 !important; }
58
 
59
+ /* Remove drag & drop + limit lines — keep Browse button */
60
+ [data-testid="stFileUploadDropzone"] p,
61
  [data-testid="stFileUploadDropzone"] [data-testid="stFileUploaderInstructions"],
62
+ [data-testid="stFileUploadDropzone"] [data-testid="stCaptionContainer"]{
63
+ display:none !important;
64
+ }
65
 
66
+ /* Pinned title/helper area */
67
+ .pinned-top{
68
+ position:sticky; top:0; z-index:999; background:#fff; padding-top:4px;
69
+ }
70
+
71
+ /* Center every table cell we render via HTML */
72
  .table-center table { margin-left:auto; margin-right:auto; border-collapse:collapse; }
73
  .table-center table th, .table-center table td {
74
  text-align:center !important; padding:6px 10px; border:1px solid #e5e7eb;
 
80
  )
81
 
82
  # =========================
83
+ # Password gate
84
  # =========================
85
  def inline_logo(path="logo.png") -> str:
86
  try:
 
147
  # =========================
148
  # Utilities
149
  # =========================
 
 
 
 
 
 
 
 
 
 
 
150
  def rmse(y_true, y_pred) -> float:
151
  return float(np.sqrt(mean_squared_error(y_true, y_pred)))
152
 
153
  def corrcoef_safe(y_true, y_pred) -> float:
154
  a = pd.Series(y_true, dtype=float)
155
  b = pd.Series(y_pred, dtype=float)
156
+ m = np.isfinite(a) & np.isfinite(b)
157
+ if not m.any(): return float("nan")
158
+ return float(np.corrcoef(a[m], b[m])[0, 1])
 
 
 
159
 
160
  @st.cache_resource(show_spinner=False)
161
  def load_model(model_path: str):
 
232
  margin=dict(l=64, r=18, t=10, b=48), hovermode="closest",
233
  font=dict(size=FONT_SZ)
234
  )
 
235
  axis_common = dict(
236
  range=[lo, hi], ticks="outside", tickformat=",.0f",
237
  tick0=tick0, dtick=step,
 
249
  y = pd.Series(df[depth_col]).astype(float)
250
  ylab = depth_col
251
  y_min, y_max = float(y.min()), float(y.max())
252
+ y_range = [y_max, y_min]
253
  else:
254
  y = pd.Series(np.arange(1, len(df) + 1))
255
  ylab = "Point Index"
256
  y_min, y_max = float(y.min()), float(y.max())
257
  y_range = [y_max, y_min]
258
 
 
259
  x_series = pd.Series(df.get("UCS_Pred", pd.Series(dtype=float))).astype(float)
260
  if include_actual and TARGET in df.columns:
261
  x_series = pd.concat([x_series, pd.Series(df[TARGET]).astype(float)], ignore_index=True)
 
312
  if n == 0:
313
  fig, ax = plt.subplots(figsize=(4, 2))
314
  ax.text(0.5,0.5,"No selected columns",ha="center",va="center")
315
+ ax.axis("off"); return fig
 
316
  fig, axes = plt.subplots(1, n, figsize=(2.2*n, 7.0), sharey=True, dpi=100)
317
  if n == 1: axes = [axes]
318
  idx = np.arange(1, len(df) + 1)
 
353
  html_table_center(tbl, index=False)
354
 
355
  # =========================
356
+ # Load model
357
  # =========================
358
  def ensure_model() -> Path|None:
359
  for p in [DEFAULT_MODEL, *MODEL_FALLBACKS]:
 
449
  df0 = next(iter(tmp.values()))
450
  st.sidebar.caption(f"**Data loaded:** {st.session_state.dev_file_name} • {df0.shape[0]} rows × {df0.shape[1]} cols")
451
 
452
+ # ---- Pinned title/helper FIRST (so it never appears below preview) ----
453
+ st.markdown('<div class="pinned-top">', unsafe_allow_html=True)
454
+ st.subheader("Case Building")
455
+ if st.session_state.dev_file_loaded and st.session_state.dev_preview:
456
+ st.info("Previewed ✓ — now click **Run Model**.")
457
+ elif st.session_state.dev_file_loaded:
458
+ st.info("📄 **Preview uploaded data** using the sidebar button, then click **Run Model**.")
459
+ else:
460
+ st.write("**Upload your data to build a case, then run the model to review development performance.**")
461
+ st.markdown('</div>', unsafe_allow_html=True)
462
+
463
  # Preview button ALWAYS enabled
464
  if st.sidebar.button("Preview data", use_container_width=True):
465
  if not st.session_state.dev_file_loaded:
 
472
  if st.sidebar.button("Proceed to Validation â–¶", use_container_width=True): st.session_state.app_step="validate"; st.rerun()
473
  if st.sidebar.button("Proceed to Prediction â–¶", use_container_width=True): st.session_state.app_step="predict"; st.rerun()
474
 
 
 
 
 
 
 
 
 
 
 
 
475
  if run and st.session_state.dev_file_bytes:
476
  book = read_book_bytes(st.session_state.dev_file_bytes)
477
  sh_train = find_sheet(book, ["Train","Training","training2","train","training"])
 
506
  c1.metric("R", f"{m['R']:.4f}"); c2.metric("RMSE", f"{m['RMSE']:.4f}"); c3.metric("MAE", f"{m['MAE']:.4f}")
507
  left, spacer, right = st.columns(PLOT_COLS)
508
  with left:
509
+ pad, plotcol = left.columns([CROSS_NUDGE, 1])
510
  with plotcol:
511
  st.plotly_chart(cross_plot(df[TARGET], df["UCS_Pred"]),
512
  use_container_width=False, config={"displayModeBar": False, "scrollZoom": True})
 
533
  df0 = next(iter(book.values()))
534
  st.sidebar.caption(f"**Data loaded:** {up.name} • {df0.shape[0]} rows × {df0.shape[1]} cols")
535
 
536
+ # pinned title/helper first
537
+ st.markdown('<div class="pinned-top">', unsafe_allow_html=True)
538
+ st.subheader("Validate the Model")
539
+ st.write("Upload a dataset with the same **features** and **UCS** to evaluate performance.")
540
+ st.markdown('</div>', unsafe_allow_html=True)
541
+
542
  if st.sidebar.button("Preview data", use_container_width=True):
543
  if up is None:
544
  st.warning("Upload an Excel file first, then preview.")
545
  else:
546
  preview_modal(read_book_bytes(up.getvalue()))
 
547
  go_btn = st.sidebar.button("Predict", type="primary", use_container_width=True)
548
  if st.sidebar.button("⬅ Back to Case Building", use_container_width=True): st.session_state.app_step="dev"; st.rerun()
549
  if st.sidebar.button("Proceed to Prediction â–¶", use_container_width=True): st.session_state.app_step="predict"; st.rerun()
550
 
 
 
 
 
551
  if go_btn and up is not None:
552
  book = read_book_bytes(up.getvalue())
553
  name = find_sheet(book, ["Validation","Validate","validation2","Val","val"]) or list(book.keys())[0]
 
610
  df0 = next(iter(book.values()))
611
  st.sidebar.caption(f"**Data loaded:** {up.name} • {df0.shape[0]} rows × {df0.shape[1]} cols")
612
 
613
+ # pinned title/helper first
614
+ st.markdown('<div class="pinned-top">', unsafe_allow_html=True)
615
+ st.subheader("Prediction")
616
+ st.write("Upload a dataset with the feature columns (no **UCS**).")
617
+ st.markdown('</div>', unsafe_allow_html=True)
618
+
619
  if st.sidebar.button("Preview data", use_container_width=True):
620
  if up is None:
621
  st.warning("Upload an Excel file first, then preview.")
622
  else:
623
  preview_modal(read_book_bytes(up.getvalue()))
 
624
  go_btn = st.sidebar.button("Predict", type="primary", use_container_width=True)
625
  if st.sidebar.button("⬅ Back to Case Building", use_container_width=True): st.session_state.app_step="dev"; st.rerun()
626
 
 
 
 
 
627
  if go_btn and up is not None:
628
  book = read_book_bytes(up.getvalue()); name = list(book.keys())[0]
629
  df = book[name].copy()