Spaces:
Sleeping
Sleeping
Rename app.py to app_toc.py
Browse files- app.py → app_toc.py +41 -51
app.py → app_toc.py
RENAMED
|
@@ -20,24 +20,16 @@ from sklearn.metrics import mean_squared_error # MAE removed
|
|
| 20 |
# =========================
|
| 21 |
# Constants / Defaults
|
| 22 |
# =========================
|
| 23 |
-
APP_NAME = "
|
| 24 |
-
TAGLINE = "Real-Time
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
"WOB (klbf)",
|
| 30 |
-
"Torque (kft.lbf)",
|
| 31 |
-
"SPP (psi)",
|
| 32 |
-
"RPM (1/min)",
|
| 33 |
-
"ROP (ft/h)",
|
| 34 |
-
"Flow Rate (gpm)",
|
| 35 |
-
]
|
| 36 |
-
TARGET = "UCS"
|
| 37 |
-
PRED_COL = "UCS_Pred"
|
| 38 |
|
| 39 |
MODELS_DIR = Path("models")
|
| 40 |
-
DEFAULT_MODEL = MODELS_DIR / "
|
|
|
|
| 41 |
MODEL_FALLBACKS = [MODELS_DIR / "model.joblib", MODELS_DIR / "model.pkl"]
|
| 42 |
COLORS = {"pred": "#1f77b4", "actual": "#f2b702", "ref": "#5a5a5a"}
|
| 43 |
|
|
@@ -165,42 +157,40 @@ def read_book_bytes(b: bytes):
|
|
| 165 |
|
| 166 |
# ---- Canonical feature aliasing (accept legacy headers) ----
|
| 167 |
def _build_alias_map(canonical_features: list[str], target_name: str) -> dict:
|
| 168 |
-
|
| 169 |
-
Map common header variants -> canonical names (from meta FEATURES).
|
| 170 |
-
"""
|
| 171 |
-
def pick(expected_list, variants):
|
| 172 |
for v in variants:
|
| 173 |
-
if v in
|
| 174 |
-
return v
|
| 175 |
return variants[0]
|
| 176 |
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
|
|
|
|
|
|
| 184 |
|
| 185 |
alias = {
|
| 186 |
-
|
| 187 |
-
"
|
| 188 |
-
"
|
| 189 |
-
"
|
| 190 |
-
"
|
| 191 |
-
"
|
| 192 |
-
"
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
"
|
| 200 |
-
"UCS_Actual": target_name,
|
| 201 |
}
|
| 202 |
return alias
|
| 203 |
|
|
|
|
| 204 |
def _normalize_columns(df: pd.DataFrame, canonical_features: list[str], target_name: str) -> pd.DataFrame:
|
| 205 |
out = df.copy()
|
| 206 |
out.columns = [str(c).strip().replace(" ,", ",").replace(", ", ", ").replace(" ", " ") for c in out.columns]
|
|
@@ -368,7 +358,7 @@ def build_export_workbook(selected: list[str] | None = None) -> tuple[bytes|None
|
|
| 368 |
df.to_excel(writer, sheet_name=_excel_safe_name(name), index=False)
|
| 369 |
bio.seek(0)
|
| 370 |
|
| 371 |
-
fname = f"
|
| 372 |
return bio.getvalue(), fname, order
|
| 373 |
|
| 374 |
def render_export_button(phase_key: str) -> None:
|
|
@@ -405,7 +395,7 @@ def render_export_button(phase_key: str) -> None:
|
|
| 405 |
st.download_button(
|
| 406 |
"⬇️ Export Excel",
|
| 407 |
data=(data or b""),
|
| 408 |
-
file_name=(fname or "
|
| 409 |
mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
| 410 |
disabled=(data is None),
|
| 411 |
key=f"download_{phase_key}",
|
|
@@ -437,8 +427,8 @@ def cross_plot_static(actual, pred):
|
|
| 437 |
fmt = FuncFormatter(lambda x, _: f"{x:,.0f}")
|
| 438 |
ax.xaxis.set_major_formatter(fmt); ax.yaxis.set_major_formatter(fmt)
|
| 439 |
|
| 440 |
-
ax.set_xlabel("Actual
|
| 441 |
-
ax.set_ylabel("Predicted
|
| 442 |
ax.tick_params(labelsize=6, colors="black")
|
| 443 |
|
| 444 |
ax.grid(True, linestyle=":", alpha=0.3)
|
|
@@ -492,9 +482,9 @@ def track_plot(df, include_actual=True):
|
|
| 492 |
legend=dict(x=0.98, y=0.05, xanchor="right", yanchor="bottom",
|
| 493 |
bgcolor="rgba(255,255,255,0.75)", bordercolor="#ccc", borderwidth=1),
|
| 494 |
legend_title_text=""
|
| 495 |
-
)
|
| 496 |
fig.update_xaxes(
|
| 497 |
-
title_text="
|
| 498 |
title_font=dict(size=20, family=BOLD_FONT, color="#000"),
|
| 499 |
tickfont=dict(size=12, family=BOLD_FONT, color="#000"),
|
| 500 |
side="top", range=[xmin, xmax],
|
|
@@ -588,7 +578,7 @@ except Exception as e:
|
|
| 588 |
|
| 589 |
# Prefer UCS-specific meta
|
| 590 |
meta = {}
|
| 591 |
-
meta_candidates = [MODELS_DIR / "
|
| 592 |
meta_path = next((p for p in meta_candidates if p.exists()), None)
|
| 593 |
if meta_path:
|
| 594 |
try:
|
|
|
|
| 20 |
# =========================
|
| 21 |
# Constants / Defaults
|
| 22 |
# =========================
|
| 23 |
+
APP_NAME = "ST_GeoMech_TOC"
|
| 24 |
+
TAGLINE = "Real-Time Total Organic Carbon Estimation While Drilling"
|
| 25 |
+
|
| 26 |
+
FEATURES = ["AHT90", "DT", "GR", "K", "RHOB", "TNPH", "Th", "Ur"]
|
| 27 |
+
TARGET = "TOC"
|
| 28 |
+
PRED_COL = "TOC_Pred"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
MODELS_DIR = Path("models")
|
| 31 |
+
DEFAULT_MODEL = MODELS_DIR / "toc_rf.joblib" # <— point to your TOC model
|
| 32 |
+
|
| 33 |
MODEL_FALLBACKS = [MODELS_DIR / "model.joblib", MODELS_DIR / "model.pkl"]
|
| 34 |
COLORS = {"pred": "#1f77b4", "actual": "#f2b702", "ref": "#5a5a5a"}
|
| 35 |
|
|
|
|
| 157 |
|
| 158 |
# ---- Canonical feature aliasing (accept legacy headers) ----
|
| 159 |
def _build_alias_map(canonical_features: list[str], target_name: str) -> dict:
|
| 160 |
+
def pick(expected, variants):
|
|
|
|
|
|
|
|
|
|
| 161 |
for v in variants:
|
| 162 |
+
if v in expected: return v
|
|
|
|
| 163 |
return variants[0]
|
| 164 |
|
| 165 |
+
# TOC logs/features
|
| 166 |
+
can_GR = pick(canonical_features, ["GR", "Gamma Ray", "GR (API)"])
|
| 167 |
+
can_RHOB = pick(canonical_features, ["RHOB", "Bulk Density", "RHOB (g/cc)"])
|
| 168 |
+
can_DT = pick(canonical_features, ["DT", "AC", "DT (us/ft)"])
|
| 169 |
+
can_TNPH = pick(canonical_features, ["TNPH", "NPHI", "TNPH (%)"])
|
| 170 |
+
can_K = pick(canonical_features, ["K", "Potassium", "K (%)"])
|
| 171 |
+
can_Th = pick(canonical_features, ["Th", "Thorium", "Th (ppm)"])
|
| 172 |
+
can_Ur = pick(canonical_features, ["Ur", "U", "U (ppm)"])
|
| 173 |
+
can_AHT = pick(canonical_features, ["AHT90", "AHT_90", "AHT-90"])
|
| 174 |
|
| 175 |
alias = {
|
| 176 |
+
"GR": can_GR, "Gamma Ray": can_GR, "GR (API)": can_GR,
|
| 177 |
+
"RHOB": can_RHOB, "Bulk Density": can_RHOB, "RHOB (g/cc)": can_RHOB,
|
| 178 |
+
"DT": can_DT, "AC": can_DT, "DT (us/ft)": can_DT,
|
| 179 |
+
"TNPH": can_TNPH, "NPHI": can_TNPH, "TNPH (%)": can_TNPH,
|
| 180 |
+
"K": can_K, "Potassium": can_K, "K (%)": can_K,
|
| 181 |
+
"Th": can_Th, "Thorium": can_Th, "Th (ppm)": can_Th,
|
| 182 |
+
"Ur": can_Ur, "U": can_Ur, "U (ppm)": can_Ur,
|
| 183 |
+
"AHT90": can_AHT, "AHT_90": can_AHT, "AHT-90": can_AHT,
|
| 184 |
+
|
| 185 |
+
# Optional depth for tracks
|
| 186 |
+
"Depth (ft)": "Depth (ft)", "DEPTH": "Depth (ft)", "MD (ft)": "Depth (ft)",
|
| 187 |
+
|
| 188 |
+
# Targets
|
| 189 |
+
"TOC": target_name, "TOC (%)": target_name, "Total Organic Carbon": target_name,
|
|
|
|
| 190 |
}
|
| 191 |
return alias
|
| 192 |
|
| 193 |
+
|
| 194 |
def _normalize_columns(df: pd.DataFrame, canonical_features: list[str], target_name: str) -> pd.DataFrame:
|
| 195 |
out = df.copy()
|
| 196 |
out.columns = [str(c).strip().replace(" ,", ",").replace(", ", ", ").replace(" ", " ") for c in out.columns]
|
|
|
|
| 358 |
df.to_excel(writer, sheet_name=_excel_safe_name(name), index=False)
|
| 359 |
bio.seek(0)
|
| 360 |
|
| 361 |
+
fname = f"TOC_Export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
|
| 362 |
return bio.getvalue(), fname, order
|
| 363 |
|
| 364 |
def render_export_button(phase_key: str) -> None:
|
|
|
|
| 395 |
st.download_button(
|
| 396 |
"⬇️ Export Excel",
|
| 397 |
data=(data or b""),
|
| 398 |
+
file_name=(fname or "TOC_Export.xlsx"),
|
| 399 |
mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
| 400 |
disabled=(data is None),
|
| 401 |
key=f"download_{phase_key}",
|
|
|
|
| 427 |
fmt = FuncFormatter(lambda x, _: f"{x:,.0f}")
|
| 428 |
ax.xaxis.set_major_formatter(fmt); ax.yaxis.set_major_formatter(fmt)
|
| 429 |
|
| 430 |
+
ax.set_xlabel("Actual TOC (%)", fontweight="bold", fontsize=10, color="black")
|
| 431 |
+
ax.set_ylabel("Predicted TOC (%)", fontweight="bold", fontsize=10, color="black")
|
| 432 |
ax.tick_params(labelsize=6, colors="black")
|
| 433 |
|
| 434 |
ax.grid(True, linestyle=":", alpha=0.3)
|
|
|
|
| 482 |
legend=dict(x=0.98, y=0.05, xanchor="right", yanchor="bottom",
|
| 483 |
bgcolor="rgba(255,255,255,0.75)", bordercolor="#ccc", borderwidth=1),
|
| 484 |
legend_title_text=""
|
| 485 |
+
)
|
| 486 |
fig.update_xaxes(
|
| 487 |
+
title_text="TOC (%)",
|
| 488 |
title_font=dict(size=20, family=BOLD_FONT, color="#000"),
|
| 489 |
tickfont=dict(size=12, family=BOLD_FONT, color="#000"),
|
| 490 |
side="top", range=[xmin, xmax],
|
|
|
|
| 578 |
|
| 579 |
# Prefer UCS-specific meta
|
| 580 |
meta = {}
|
| 581 |
+
meta_candidates = [MODELS_DIR / "toc_meta.json", MODELS_DIR / "meta.json"]
|
| 582 |
meta_path = next((p for p in meta_candidates if p.exists()), None)
|
| 583 |
if meta_path:
|
| 584 |
try:
|