Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -26,11 +26,14 @@ MODEL_FALLBACKS = [MODELS_DIR / "model.joblib", MODELS_DIR / "model.pkl"]
|
|
| 26 |
COLORS = {"pred": "#1f77b4", "actual": "#f2b702", "ref": "#5a5a5a"}
|
| 27 |
|
| 28 |
# ---- Plot sizing controls ----
|
| 29 |
-
CROSS_W =
|
| 30 |
-
|
|
|
|
|
|
|
| 31 |
FONT_SZ = 15
|
| 32 |
-
PLOT_COLS = [
|
| 33 |
-
CROSS_NUDGE = 0.
|
|
|
|
| 34 |
|
| 35 |
# =========================
|
| 36 |
# Page / CSS
|
|
@@ -167,131 +170,59 @@ def _nice_tick0(xmin: float, step: int = 100) -> float:
|
|
| 167 |
# =========================
|
| 168 |
# Cross-plot (Matplotlib, static)
|
| 169 |
# =========================
|
|
|
|
|
|
|
|
|
|
| 170 |
def cross_plot_static(actual, pred):
|
| 171 |
-
a = pd.Series(actual
|
| 172 |
-
p = pd.Series(pred
|
| 173 |
|
| 174 |
fixed_min, fixed_max = 6000, 10000
|
| 175 |
-
ticks = np.arange(
|
| 176 |
|
| 177 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 178 |
|
| 179 |
-
|
|
|
|
| 180 |
|
| 181 |
# 1:1 diagonal
|
| 182 |
ax.plot([fixed_min, fixed_max], [fixed_min, fixed_max],
|
| 183 |
linestyle="--", linewidth=1.2, color=COLORS["ref"])
|
| 184 |
|
| 185 |
-
#
|
| 186 |
ax.set_xlim(fixed_min, fixed_max)
|
| 187 |
ax.set_ylim(fixed_min, fixed_max)
|
| 188 |
ax.set_xticks(ticks)
|
| 189 |
ax.set_yticks(ticks)
|
| 190 |
|
| 191 |
-
#
|
| 192 |
-
ax.set_aspect(
|
| 193 |
|
| 194 |
-
#
|
| 195 |
fmt = FuncFormatter(lambda x, _: f"{int(x):,}")
|
| 196 |
ax.xaxis.set_major_formatter(fmt)
|
| 197 |
ax.yaxis.set_major_formatter(fmt)
|
| 198 |
|
| 199 |
-
#
|
| 200 |
ax.set_xlabel("Actual UCS (psi)", fontweight="bold", fontsize=16)
|
| 201 |
ax.set_ylabel("Predicted UCS (psi)", fontweight="bold", fontsize=16)
|
| 202 |
|
| 203 |
-
#
|
| 204 |
ax.grid(True, linestyle=":", alpha=0.35)
|
| 205 |
for spine in ax.spines.values():
|
| 206 |
-
spine.set_visible(True)
|
| 207 |
spine.set_linewidth(1.2)
|
| 208 |
spine.set_color("#444")
|
| 209 |
|
| 210 |
-
|
| 211 |
-
|
| 212 |
|
| 213 |
-
# =========================
|
| 214 |
-
# Track plot (Plotly)
|
| 215 |
-
# =========================
|
| 216 |
-
def track_plot(df, include_actual=True):
|
| 217 |
-
depth_col = next((c for c in df.columns if 'depth' in str(c).lower()), None)
|
| 218 |
-
if depth_col is not None:
|
| 219 |
-
y = pd.Series(df[depth_col]).astype(float)
|
| 220 |
-
ylab = depth_col
|
| 221 |
-
y_range = [float(y.max()), float(y.min())] # reverse
|
| 222 |
-
else:
|
| 223 |
-
y = pd.Series(np.arange(1, len(df) + 1))
|
| 224 |
-
ylab = "Point Index"
|
| 225 |
-
y_range = [float(y.max()), float(y.min())]
|
| 226 |
-
|
| 227 |
-
# X (UCS) range & ticks
|
| 228 |
-
x_series = pd.Series(df.get("UCS_Pred", pd.Series(dtype=float))).astype(float)
|
| 229 |
-
if include_actual and TARGET in df.columns:
|
| 230 |
-
x_series = pd.concat([x_series, pd.Series(df[TARGET]).astype(float)], ignore_index=True)
|
| 231 |
-
x_lo, x_hi = float(x_series.min()), float(x_series.max())
|
| 232 |
-
x_pad = 0.03 * (x_hi - x_lo if x_hi > x_lo else 1.0)
|
| 233 |
-
xmin, xmax = x_lo - x_pad, x_hi + x_pad
|
| 234 |
-
tick0 = _nice_tick0(xmin, step=100)
|
| 235 |
-
|
| 236 |
-
fig = go.Figure()
|
| 237 |
-
fig.add_trace(go.Scatter(
|
| 238 |
-
x=df["UCS_Pred"], y=y, mode="lines",
|
| 239 |
-
line=dict(color=COLORS["pred"], width=1.8),
|
| 240 |
-
name="UCS_Pred",
|
| 241 |
-
hovertemplate="UCS_Pred: %{x:.0f}<br>"+ylab+": %{y}<extra></extra>"
|
| 242 |
-
))
|
| 243 |
-
if include_actual and TARGET in df.columns:
|
| 244 |
-
fig.add_trace(go.Scatter(
|
| 245 |
-
x=df[TARGET], y=y, mode="lines",
|
| 246 |
-
line=dict(color=COLORS["actual"], width=2.0, dash="dot"),
|
| 247 |
-
name="UCS (actual)",
|
| 248 |
-
hovertemplate="UCS (actual): %{x:.0f}<br>"+ylab+": %{y}<extra></extra>"
|
| 249 |
-
))
|
| 250 |
-
|
| 251 |
-
fig.update_layout(
|
| 252 |
-
width=TRACK_W, height=TRACK_H, paper_bgcolor="#fff", plot_bgcolor="#fff",
|
| 253 |
-
margin=dict(l=72, r=18, t=36, b=48), hovermode="closest",
|
| 254 |
-
font=dict(size=FONT_SZ),
|
| 255 |
-
legend=dict(
|
| 256 |
-
x=0.98, y=0.05, xanchor="right", yanchor="bottom",
|
| 257 |
-
bgcolor="rgba(255,255,255,0.75)", bordercolor="#ccc", borderwidth=1
|
| 258 |
-
),
|
| 259 |
-
legend_title_text=""
|
| 260 |
-
)
|
| 261 |
-
fig.update_xaxes(
|
| 262 |
-
title_text="<b>UCS (psi)</b>", title_font=dict(size=18),
|
| 263 |
-
side="top", range=[xmin, xmax],
|
| 264 |
-
ticks="outside", tickformat=",.0f", tickmode="auto", tick0=tick0,
|
| 265 |
-
showline=True, linewidth=1.2, linecolor="#444", mirror=True,
|
| 266 |
-
showgrid=True, gridcolor="rgba(0,0,0,0.12)", automargin=True
|
| 267 |
-
)
|
| 268 |
-
fig.update_yaxes(
|
| 269 |
-
title_text=f"<b>{ylab}</b>", title_font=dict(size=18),
|
| 270 |
-
range=y_range, ticks="outside",
|
| 271 |
-
showline=True, linewidth=1.2, linecolor="#444", mirror=True,
|
| 272 |
-
showgrid=True, gridcolor="rgba(0,0,0,0.12)", automargin=True
|
| 273 |
-
)
|
| 274 |
return fig
|
| 275 |
|
| 276 |
-
# ---------- Preview modal (matplotlib) ----------
|
| 277 |
-
def preview_tracks(df: pd.DataFrame, cols: list[str]):
|
| 278 |
-
cols = [c for c in cols if c in df.columns]
|
| 279 |
-
n = len(cols)
|
| 280 |
-
if n == 0:
|
| 281 |
-
fig, ax = plt.subplots(figsize=(4, 2))
|
| 282 |
-
ax.text(0.5,0.5,"No selected columns",ha="center",va="center")
|
| 283 |
-
ax.axis("off")
|
| 284 |
-
return fig
|
| 285 |
-
fig, axes = plt.subplots(1, n, figsize=(2.2*n, 7.0), sharey=True, dpi=100)
|
| 286 |
-
if n == 1: axes = [axes]
|
| 287 |
-
idx = np.arange(1, len(df) + 1)
|
| 288 |
-
for ax, col in zip(axes, cols):
|
| 289 |
-
ax.plot(df[col], idx, '-', lw=1.4, color="#333")
|
| 290 |
-
ax.set_xlabel(col); ax.xaxis.set_label_position('top'); ax.xaxis.tick_top(); ax.invert_yaxis()
|
| 291 |
-
ax.grid(True, linestyle=":", alpha=0.3)
|
| 292 |
-
for s in ax.spines.values(): s.set_visible(True)
|
| 293 |
-
axes[0].set_ylabel("Point Index")
|
| 294 |
-
return fig
|
| 295 |
|
| 296 |
try:
|
| 297 |
dialog = st.dialog
|
|
|
|
| 26 |
COLORS = {"pred": "#1f77b4", "actual": "#f2b702", "ref": "#5a5a5a"}
|
| 27 |
|
| 28 |
# ---- Plot sizing controls ----
|
| 29 |
+
CROSS_W = None # let the chart fill the column
|
| 30 |
+
CROSS_H = 420
|
| 31 |
+
TRACK_W = None # let the chart fill the column
|
| 32 |
+
TRACK_H = 820
|
| 33 |
FONT_SZ = 15
|
| 34 |
+
PLOT_COLS = [42, 2, 30] # wider left & right, a thicker spacer in the middle
|
| 35 |
+
CROSS_NUDGE = 0.0
|
| 36 |
+
|
| 37 |
|
| 38 |
# =========================
|
| 39 |
# Page / CSS
|
|
|
|
| 170 |
# =========================
|
| 171 |
# Cross-plot (Matplotlib, static)
|
| 172 |
# =========================
|
| 173 |
+
# =========================
|
| 174 |
+
# Cross plot (Matplotlib, fixed limits & ticks)
|
| 175 |
+
# =========================
|
| 176 |
def cross_plot_static(actual, pred):
|
| 177 |
+
a = pd.Series(actual, dtype=float)
|
| 178 |
+
p = pd.Series(pred, dtype=float)
|
| 179 |
|
| 180 |
fixed_min, fixed_max = 6000, 10000
|
| 181 |
+
ticks = np.arange(fixed_min, fixed_max + 1, 1000)
|
| 182 |
|
| 183 |
+
# use constrained_layout + generous margins so big labels never overlap
|
| 184 |
+
fig, ax = plt.subplots(
|
| 185 |
+
figsize=((CROSS_W or 500)/100, (CROSS_H or 500)/100),
|
| 186 |
+
dpi=100,
|
| 187 |
+
constrained_layout=True
|
| 188 |
+
)
|
| 189 |
|
| 190 |
+
# points
|
| 191 |
+
ax.scatter(a, p, s=18, c=COLORS["pred"], alpha=0.9, linewidths=0)
|
| 192 |
|
| 193 |
# 1:1 diagonal
|
| 194 |
ax.plot([fixed_min, fixed_max], [fixed_min, fixed_max],
|
| 195 |
linestyle="--", linewidth=1.2, color=COLORS["ref"])
|
| 196 |
|
| 197 |
+
# identical axes limits + ticks
|
| 198 |
ax.set_xlim(fixed_min, fixed_max)
|
| 199 |
ax.set_ylim(fixed_min, fixed_max)
|
| 200 |
ax.set_xticks(ticks)
|
| 201 |
ax.set_yticks(ticks)
|
| 202 |
|
| 203 |
+
# equal aspect → true 45° reference
|
| 204 |
+
ax.set_aspect("equal", adjustable="box")
|
| 205 |
|
| 206 |
+
# thousands formatting
|
| 207 |
fmt = FuncFormatter(lambda x, _: f"{int(x):,}")
|
| 208 |
ax.xaxis.set_major_formatter(fmt)
|
| 209 |
ax.yaxis.set_major_formatter(fmt)
|
| 210 |
|
| 211 |
+
# labels (bold, larger)
|
| 212 |
ax.set_xlabel("Actual UCS (psi)", fontweight="bold", fontsize=16)
|
| 213 |
ax.set_ylabel("Predicted UCS (psi)", fontweight="bold", fontsize=16)
|
| 214 |
|
| 215 |
+
# grid & frame
|
| 216 |
ax.grid(True, linestyle=":", alpha=0.35)
|
| 217 |
for spine in ax.spines.values():
|
|
|
|
| 218 |
spine.set_linewidth(1.2)
|
| 219 |
spine.set_color("#444")
|
| 220 |
|
| 221 |
+
# extra room for the large labels
|
| 222 |
+
fig.subplots_adjust(left=0.23, bottom=0.20, right=0.98, top=0.98)
|
| 223 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
return fig
|
| 225 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
|
| 227 |
try:
|
| 228 |
dialog = st.dialog
|