Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -51,6 +51,31 @@ FONT_SZ = 13
|
|
| 51 |
BOLD_FONT = "Arial Black, Arial, sans-serif"
|
| 52 |
PLAIN_FONT = "Arial, sans-serif"
|
| 53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
# =========================
|
| 55 |
# Page / CSS
|
| 56 |
# =========================
|
|
@@ -330,11 +355,13 @@ def cross_plot_static(actual, pred, xlabel, ylabel, color="#1f77b4"):
|
|
| 330 |
def _depth_series(df):
|
| 331 |
depth_col = next((c for c in df.columns if 'depth' in str(c).lower()), None)
|
| 332 |
if depth_col is not None:
|
| 333 |
-
y = pd.to_numeric(df[depth_col], errors="coerce");
|
| 334 |
rng = [float(y.max()), float(y.min())] # reversed
|
| 335 |
else:
|
| 336 |
-
y = pd.Series(np.arange(1, len(df) + 1));
|
| 337 |
rng = [float(y.max()), float(y.min())]
|
|
|
|
|
|
|
| 338 |
return y, ylab, rng
|
| 339 |
|
| 340 |
def _x_range_for_tracks(df, cols):
|
|
@@ -366,7 +393,7 @@ def track_plot_single(df, pred_col, actual_col=None, title_suffix=""):
|
|
| 366 |
bgcolor="rgba(255,255,255,0.75)", bordercolor="#ccc", borderwidth=1),
|
| 367 |
legend_title_text="", title=title_suffix)
|
| 368 |
fig.update_xaxes(
|
| 369 |
-
title_text=
|
| 370 |
title_font=dict(size=20, family=BOLD_FONT, color="#000"),
|
| 371 |
tickfont=dict(size=15, family=PLAIN_FONT, color="#000"),
|
| 372 |
side="top", range=[xmin, xmax], ticks="outside", tickformat=",.2f",
|
|
@@ -412,7 +439,7 @@ def track_plot_combined(df):
|
|
| 412 |
bgcolor="rgba(255,255,255,0.75)", bordercolor="#ccc", borderwidth=1),
|
| 413 |
legend_title_text="", title="Combined (Breakout / Breakdown)")
|
| 414 |
fig.update_xaxes(
|
| 415 |
-
title_text=
|
| 416 |
title_font=dict(size=20, family=BOLD_FONT, color="#000"),
|
| 417 |
tickfont=dict(size=15, family=PLAIN_FONT, color="#000"),
|
| 418 |
side="top", range=[xmin, xmax], ticks="outside", tickformat=",.2f",
|
|
@@ -649,7 +676,6 @@ if st.session_state.app_step == "dev":
|
|
| 649 |
_metrics_block("BO", mbo); _metrics_block("BD", mbd)
|
| 650 |
st.markdown("<div style='text-align:left;font-size:0.8em;color:#6b7280;margin-top:-16px;margin-bottom:8px;'><strong>R</strong> = Pearson correlation • <strong>RMSE/MAE</strong> in MW (pcf)</div>", unsafe_allow_html=True)
|
| 651 |
t1, t2, t3 = st.tabs(["Breakout", "Breakdown", "Combined"])
|
| 652 |
-
units = st.session_state.get("X_UNITS","MW (pcf)")
|
| 653 |
with t1:
|
| 654 |
left, right = st.columns([3,1], gap="large")
|
| 655 |
with left:
|
|
@@ -658,11 +684,9 @@ if st.session_state.app_step == "dev":
|
|
| 658 |
use_container_width=False, config={"displayModeBar": False, "scrollZoom": True}
|
| 659 |
)
|
| 660 |
with right:
|
|
|
|
| 661 |
st.pyplot(
|
| 662 |
-
cross_plot_static(df[TARGET_BO], df[PRED_BO],
|
| 663 |
-
f"Actual {TARGET_BO} ({units})",
|
| 664 |
-
f"Predicted {TARGET_BO} ({units})",
|
| 665 |
-
COLORS["pred_bo"]),
|
| 666 |
use_container_width=False
|
| 667 |
)
|
| 668 |
with t2:
|
|
@@ -673,11 +697,9 @@ if st.session_state.app_step == "dev":
|
|
| 673 |
use_container_width=False, config={"displayModeBar": False, "scrollZoom": True}
|
| 674 |
)
|
| 675 |
with right:
|
|
|
|
| 676 |
st.pyplot(
|
| 677 |
-
cross_plot_static(df[TARGET_BD], df[PRED_BD],
|
| 678 |
-
f"Actual {TARGET_BD} ({units})",
|
| 679 |
-
f"Predicted {TARGET_BD} ({units})",
|
| 680 |
-
COLORS["pred_bd"]),
|
| 681 |
use_container_width=False
|
| 682 |
)
|
| 683 |
with t3:
|
|
@@ -741,11 +763,10 @@ if st.session_state.app_step == "validate":
|
|
| 741 |
c1,c2,c3 = st.columns(3)
|
| 742 |
c1.metric("R (BO)", f"{m_bo['R']:.3f}"); c2.metric("RMSE (BO)", f"{m_bo['RMSE']:.2f}"); c3.metric("MAE (BO)", f"{m_bo['MAE']:.2f}")
|
| 743 |
c1,c2,c3 = st.columns(3)
|
| 744 |
-
c1.metric("R (BD)", f"{m_bd['R']:.3f}"); c2.metric("RMSE (BD)", f"{m_bd['RMSE']:.2f}"); c3.metric("MAE (BD)", f"{m_bd['MAE']:.2f}")
|
| 745 |
st.markdown("<div style='text-align:left;font-size:0.8em;color:#6b7280;margin-top:-16px;margin-bottom:8px;'>R = Pearson correlation</div>", unsafe_allow_html=True)
|
| 746 |
|
| 747 |
t1, t2, t3 = st.tabs(["Breakout", "Breakdown", "Combined"])
|
| 748 |
-
units = st.session_state.get("X_UNITS","MW (pcf)")
|
| 749 |
with t1:
|
| 750 |
left, right = st.columns([3,1], gap="large")
|
| 751 |
with left:
|
|
@@ -754,11 +775,9 @@ if st.session_state.app_step == "validate":
|
|
| 754 |
use_container_width=False, config={"displayModeBar": False, "scrollZoom": True}
|
| 755 |
)
|
| 756 |
with right:
|
|
|
|
| 757 |
st.pyplot(
|
| 758 |
-
cross_plot_static(df[TARGET_BO], df[PRED_BO],
|
| 759 |
-
f"Actual {TARGET_BO} ({units})",
|
| 760 |
-
f"Predicted {TARGET_BO} ({units})",
|
| 761 |
-
COLORS["pred_bo"]),
|
| 762 |
use_container_width=False
|
| 763 |
)
|
| 764 |
with t2:
|
|
@@ -769,11 +788,9 @@ if st.session_state.app_step == "validate":
|
|
| 769 |
use_container_width=False, config={"displayModeBar": False, "scrollZoom": True}
|
| 770 |
)
|
| 771 |
with right:
|
|
|
|
| 772 |
st.pyplot(
|
| 773 |
-
cross_plot_static(df[TARGET_BD], df[PRED_BD],
|
| 774 |
-
f"Actual {TARGET_BD} ({units})",
|
| 775 |
-
f"Predicted {TARGET_BD} ({units})",
|
| 776 |
-
COLORS["pred_bd"]),
|
| 777 |
use_container_width=False
|
| 778 |
)
|
| 779 |
with t3:
|
|
@@ -864,6 +881,7 @@ if st.session_state.show_preview_modal:
|
|
| 864 |
for t, name in zip(tabs, names):
|
| 865 |
with t:
|
| 866 |
df = book_to_preview[name]
|
|
|
|
| 867 |
missing = [c for c in st.session_state["FEATURES"] if c not in df.columns]
|
| 868 |
st.write("**Missing vs required features:**", missing if missing else "None ✅")
|
| 869 |
t1, t2 = st.tabs(["Tracks", "Summary"])
|
|
|
|
| 51 |
BOLD_FONT = "Arial Black, Arial, sans-serif"
|
| 52 |
PLAIN_FONT = "Arial, sans-serif"
|
| 53 |
|
| 54 |
+
# ===== Axis Titles (easy to edit) ===========================================
|
| 55 |
+
# Track plots: set either to a string to override, or leave as None to use defaults.
|
| 56 |
+
X_AXIS_TITLE_OVERRIDE = "Breakout Limit (pcf)" # e.g., "Mud Weight (pcf)"
|
| 57 |
+
Y_AXIS_TITLE_OVERRIDE = Depth (ft) # e.g., "Depth (ft)"
|
| 58 |
+
|
| 59 |
+
# Cross-plot axis titles. You can use {units} and it will fill from meta.
|
| 60 |
+
CROSS_TITLES = {
|
| 61 |
+
"bo": {"x": "Actual Breakout Limit ({units})", "y": "Predicted Breakout Limit ({units})"},
|
| 62 |
+
"bd": {"x": "Actual Breakdown Limit ({units})", "y": "Predicted Breakdown Limit ({units})"},
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
def _track_x_title() -> str:
|
| 66 |
+
return X_AXIS_TITLE_OVERRIDE or st.session_state.get("X_UNITS", "MW (pcf)")
|
| 67 |
+
|
| 68 |
+
def _track_y_title(default_ylab: str) -> str:
|
| 69 |
+
return Y_AXIS_TITLE_OVERRIDE or default_ylab
|
| 70 |
+
|
| 71 |
+
def _cross_titles(kind: str) -> tuple[str, str]:
|
| 72 |
+
units = st.session_state.get("X_UNITS", "MW (pcf)")
|
| 73 |
+
t = CROSS_TITLES.get(kind, {})
|
| 74 |
+
xlab = (t.get("x") or f"Actual {kind.upper()} ({units})").format(units=units)
|
| 75 |
+
ylab = (t.get("y") or f"Predicted {kind.upper()} ({units})").format(units=units)
|
| 76 |
+
return xlab, ylab
|
| 77 |
+
# ===========================================================================
|
| 78 |
+
|
| 79 |
# =========================
|
| 80 |
# Page / CSS
|
| 81 |
# =========================
|
|
|
|
| 355 |
def _depth_series(df):
|
| 356 |
depth_col = next((c for c in df.columns if 'depth' in str(c).lower()), None)
|
| 357 |
if depth_col is not None:
|
| 358 |
+
y = pd.to_numeric(df[depth_col], errors="coerce"); ylab_default = depth_col
|
| 359 |
rng = [float(y.max()), float(y.min())] # reversed
|
| 360 |
else:
|
| 361 |
+
y = pd.Series(np.arange(1, len(df) + 1)); ylab_default = "Point Index"
|
| 362 |
rng = [float(y.max()), float(y.min())]
|
| 363 |
+
# apply override for Y-axis title
|
| 364 |
+
ylab = _track_y_title(ylab_default)
|
| 365 |
return y, ylab, rng
|
| 366 |
|
| 367 |
def _x_range_for_tracks(df, cols):
|
|
|
|
| 393 |
bgcolor="rgba(255,255,255,0.75)", bordercolor="#ccc", borderwidth=1),
|
| 394 |
legend_title_text="", title=title_suffix)
|
| 395 |
fig.update_xaxes(
|
| 396 |
+
title_text=_track_x_title(),
|
| 397 |
title_font=dict(size=20, family=BOLD_FONT, color="#000"),
|
| 398 |
tickfont=dict(size=15, family=PLAIN_FONT, color="#000"),
|
| 399 |
side="top", range=[xmin, xmax], ticks="outside", tickformat=",.2f",
|
|
|
|
| 439 |
bgcolor="rgba(255,255,255,0.75)", bordercolor="#ccc", borderwidth=1),
|
| 440 |
legend_title_text="", title="Combined (Breakout / Breakdown)")
|
| 441 |
fig.update_xaxes(
|
| 442 |
+
title_text=_track_x_title(),
|
| 443 |
title_font=dict(size=20, family=BOLD_FONT, color="#000"),
|
| 444 |
tickfont=dict(size=15, family=PLAIN_FONT, color="#000"),
|
| 445 |
side="top", range=[xmin, xmax], ticks="outside", tickformat=",.2f",
|
|
|
|
| 676 |
_metrics_block("BO", mbo); _metrics_block("BD", mbd)
|
| 677 |
st.markdown("<div style='text-align:left;font-size:0.8em;color:#6b7280;margin-top:-16px;margin-bottom:8px;'><strong>R</strong> = Pearson correlation • <strong>RMSE/MAE</strong> in MW (pcf)</div>", unsafe_allow_html=True)
|
| 678 |
t1, t2, t3 = st.tabs(["Breakout", "Breakdown", "Combined"])
|
|
|
|
| 679 |
with t1:
|
| 680 |
left, right = st.columns([3,1], gap="large")
|
| 681 |
with left:
|
|
|
|
| 684 |
use_container_width=False, config={"displayModeBar": False, "scrollZoom": True}
|
| 685 |
)
|
| 686 |
with right:
|
| 687 |
+
xlab, ylab = _cross_titles("bo")
|
| 688 |
st.pyplot(
|
| 689 |
+
cross_plot_static(df[TARGET_BO], df[PRED_BO], xlab, ylab, COLORS["pred_bo"]),
|
|
|
|
|
|
|
|
|
|
| 690 |
use_container_width=False
|
| 691 |
)
|
| 692 |
with t2:
|
|
|
|
| 697 |
use_container_width=False, config={"displayModeBar": False, "scrollZoom": True}
|
| 698 |
)
|
| 699 |
with right:
|
| 700 |
+
xlab, ylab = _cross_titles("bd")
|
| 701 |
st.pyplot(
|
| 702 |
+
cross_plot_static(df[TARGET_BD], df[PRED_BD], xlab, ylab, COLORS["pred_bd"]),
|
|
|
|
|
|
|
|
|
|
| 703 |
use_container_width=False
|
| 704 |
)
|
| 705 |
with t3:
|
|
|
|
| 763 |
c1,c2,c3 = st.columns(3)
|
| 764 |
c1.metric("R (BO)", f"{m_bo['R']:.3f}"); c2.metric("RMSE (BO)", f"{m_bo['RMSE']:.2f}"); c3.metric("MAE (BO)", f"{m_bo['MAE']:.2f}")
|
| 765 |
c1,c2,c3 = st.columns(3)
|
| 766 |
+
c1.metric("R (BD)", f"{m_bd['R']:.3f}"); c2.metric("RMSE (BD)", f"{m_bd['RMSE']:.2f}"); c3.metric(f"MAE (BD)", f"{m_bd['MAE']:.2f}")
|
| 767 |
st.markdown("<div style='text-align:left;font-size:0.8em;color:#6b7280;margin-top:-16px;margin-bottom:8px;'>R = Pearson correlation</div>", unsafe_allow_html=True)
|
| 768 |
|
| 769 |
t1, t2, t3 = st.tabs(["Breakout", "Breakdown", "Combined"])
|
|
|
|
| 770 |
with t1:
|
| 771 |
left, right = st.columns([3,1], gap="large")
|
| 772 |
with left:
|
|
|
|
| 775 |
use_container_width=False, config={"displayModeBar": False, "scrollZoom": True}
|
| 776 |
)
|
| 777 |
with right:
|
| 778 |
+
xlab, ylab = _cross_titles("bo")
|
| 779 |
st.pyplot(
|
| 780 |
+
cross_plot_static(df[TARGET_BO], df[PRED_BO], xlab, ylab, COLORS["pred_bo"]),
|
|
|
|
|
|
|
|
|
|
| 781 |
use_container_width=False
|
| 782 |
)
|
| 783 |
with t2:
|
|
|
|
| 788 |
use_container_width=False, config={"displayModeBar": False, "scrollZoom": True}
|
| 789 |
)
|
| 790 |
with right:
|
| 791 |
+
xlab, ylab = _cross_titles("bd")
|
| 792 |
st.pyplot(
|
| 793 |
+
cross_plot_static(df[TARGET_BD], df[PRED_BD], xlab, ylab, COLORS["pred_bd"]),
|
|
|
|
|
|
|
|
|
|
| 794 |
use_container_width=False
|
| 795 |
)
|
| 796 |
with t3:
|
|
|
|
| 881 |
for t, name in zip(tabs, names):
|
| 882 |
with t:
|
| 883 |
df = book_to_preview[name]
|
| 884 |
+
# show a strict check summary, but do not stop
|
| 885 |
missing = [c for c in st.session_state["FEATURES"] if c not in df.columns]
|
| 886 |
st.write("**Missing vs required features:**", missing if missing else "None ✅")
|
| 887 |
t1, t2 = st.tabs(["Tracks", "Summary"])
|