CME / app.py
ivaan96's picture
Update app.py
e037704 verified
Raw
History Blame Contribute Delete
5.94 kB
import numpy as np
import gradio as gr
import joblib
import tensorflow as tf
import pandas as pd
MODEL_PATH = "./NN_12_feat.keras"
SCALER_PATH = "./scaler.pkl"
# 1) Cargar modelo y scaler
model = tf.keras.models.load_model(MODEL_PATH)
scaler = joblib.load(SCALER_PATH)
# 2) Definí el orden EXACTO de tus 12 features (como entrenaste)
FEATURE_NAMES = ['Angular Width (deg)',
'MPA (deg)',
'Linear Speed (km/s)',
'2nd ord. Final Linear Speed (km/s)',
'Mass (g)',
'Bx (nT)',
'Bz (nT)',
'Proton Temperature (K)',
'Flow Speed (km/s)',
'Flow Longitude (deg)',
'Alpha to Proton Ratio',
'Plasma Pressure (nPa)']
# 3) Rangos/steps/valores iniciales para sliders (ajustalos a tu dataset)
# Si no sabés rangos, poné inputs como gr.Number (más abajo te muestro opción).
'''RANGES = {
name: {"min": 0.0, "max": 1.0, "step": 0.01, "value": 0.5}
for name in FEATURE_NAMES
}'''
RANGES = {
"Angular Width (deg)": {
"min": 0, "max": 360, "step": 1, "value": 180, "unit": "deg"
},
"MPA (deg)": {
"min": 0, "max": 360, "step": 1, "value": 180, "unit": "deg"
},
"Linear Speed (km/s)": {
"min": 100, "max": 3000, "step": 10, "value": 800, "unit": "km/s"
},
"2nd ord. Final Linear Speed (km/s)": {
"min": 100, "max": 3000, "step": 10, "value": 800, "unit": "km/s"
},
"Mass (g)": {
"min": 1e12, "max": 1e17, "step": 1e12, "value": 5e14, "unit": "g"
},
"Bx (nT)": {
"min": -20, "max": 20, "step": 0.5, "value": 0, "unit": "nT"
},
"Bz (nT)": {
"min": -40, "max": 20, "step": 0.5, "value": -10, "unit": "nT"
},
"Proton Temperature (K)": {
"min": 1e3, "max": 2e6, "step": 1e3, "value": 1e5, "unit": "K"
},
"Flow Speed (km/s)": {
"min": 100, "max": 1000, "step": 10, "value": 500, "unit": "km/s"
},
"Flow Longitude (deg)": {
"min": -10, "max": 10, "step": 1, "value": 0, "unit": "deg"
},
"Alpha to Proton Ratio": {
"min": 0, "max": 10, "step": 0.005, "value": 0.02, "unit": ""
},
"Plasma Pressure (nPa)": {
"min": 0, "max": 20, "step": 0.1, "value": 2, "unit": "nPa"
}
}
# 4) Umbrales para feedback “dinámico” (en horas) - ajustá si querés
THRESH_FAST = 24
THRESH_MED = 48
def _predict_from_vector(x_raw: np.ndarray) -> float:
"""x_raw: shape (12,) sin escalar"""
x_scaled = scaler.transform(x_raw.reshape(1, -1))
y = model.predict(x_scaled, verbose=0).reshape(-1)[0]
return float(y)
def predict(*inputs):
x = np.array(inputs, dtype=float)
y = _predict_from_vector(x)
# Texto dinámico
if y <= THRESH_FAST:
label = "Rápida"
msg = f"🟢 Predicción **rápida**: **{y:.2f} h** (≤ {THRESH_FAST} h)."
elif y <= THRESH_MED:
label = "Intermedia"
msg = f"🟠 Predicción **intermedia**: **{y:.2f} h** (entre {THRESH_FAST} y {THRESH_MED} h)."
else:
label = "Lenta"
msg = f"🔴 Predicción **lenta**: **{y:.2f} h** (> {THRESH_MED} h)."
table = [[FEATURE_NAMES[i], float(x[i])] for i in range(len(FEATURE_NAMES))]
#gauge = {"value": y, "min": 0, "max": max(120, y * 1.2), "label": f"Tiempo de propagación (h) — {label}"}
return y, table, msg
'''
def what_if(feature_idx, *inputs):
x0 = np.array(inputs, dtype=float)
fname = FEATURE_NAMES[int(feature_idx)]
r = RANGES[fname]
xs = np.linspace(r["min"], r["max"], 60)
ys = []
for v in xs:
x = x0.copy()
x[int(feature_idx)] = v
ys.append(_predict_from_vector(x))
data = [{"x": float(a), "y": float(b)} for a, b in zip(xs, ys)]
title = f"Curva what-if variando: **{fname}**"
return data, title'''
def what_if(feature_idx, *inputs):
x0 = np.array(inputs, dtype=float)
idx = int(feature_idx) # por si viene como string
fname = FEATURE_NAMES[idx]
r = RANGES[fname]
xs = np.linspace(r["min"], r["max"], 60)
ys = []
for v in xs:
x = x0.copy()
x[idx] = v
ys.append(_predict_from_vector(x))
df = pd.DataFrame({"x": xs.astype(float), "y": np.array(ys, dtype=float)})
title = f"Curva what-if variando: **{fname}**"
return df, title
with gr.Blocks() as demo:
gr.Markdown(
"## Predicción del tiempo de propagación de una CME\n"
"Ingresá los 12 atributos.\n"
"Se puede explorar la sensibilidad de cada atributo mediante **what-if**."
)
with gr.Row():
with gr.Column(scale=2):
inputs = []
for name in FEATURE_NAMES:
r = RANGES[name]
inputs.append(
gr.Slider(
minimum=r["min"], maximum=r["max"], step=r["step"],
value=r["value"],
label=name
)
)
btn = gr.Button("Predecir")
with gr.Column(scale=1):
out_value = gr.Number(label="Tiempo de propagación predicho (h)", precision=2)
out_table = gr.Dataframe(headers=["Atributo", "Valor"], interactive=False, row_count=12, col_count=2)
out_text = gr.Markdown()
btn.click(predict, inputs=inputs, outputs=[out_value, out_table, out_text])
gr.Markdown("### What-if (sensibilidad)")
with gr.Row():
feature_pick = gr.Dropdown(
choices=[(f"{i}{FEATURE_NAMES[i]}", i) for i in range(len(FEATURE_NAMES))],
value=0,
label="Elegí el atributo a variar"
)
whatif_btn = gr.Button("Generar curva")
plot = gr.LinePlot(
x="x", y="y",
title="Predicción vs valor del atributo",
x_title="Valor del atributo",
y_title="Tiempo de propagación (h)",
height=350
)
plot_title = gr.Markdown()
whatif_btn.click(
what_if,
inputs=[feature_pick] + inputs,
outputs=[plot, plot_title]
)
demo.launch()