Update app.py
Browse files
app.py
CHANGED
|
@@ -49,14 +49,11 @@ def ajustar_decimales_evento(df, decimales):
|
|
| 49 |
df = df.copy()
|
| 50 |
# Ajustar decimales en todas las columnas numéricas
|
| 51 |
for col in df.columns:
|
| 52 |
-
|
|
|
|
| 53 |
df[col] = df[col].round(decimales)
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
try:
|
| 57 |
-
df[col] = pd.to_numeric(df[col], errors='ignore').round(decimales)
|
| 58 |
-
except:
|
| 59 |
-
pass
|
| 60 |
return df
|
| 61 |
|
| 62 |
def calcular_promedio_desviacion(df, n_replicas, unidad_medida):
|
|
@@ -77,7 +74,7 @@ def calcular_promedio_desviacion(df, n_replicas, unidad_medida):
|
|
| 77 |
|
| 78 |
return df
|
| 79 |
|
| 80 |
-
def generar_graficos(df_valid, n_replicas, unidad_medida, estilo_grafico):
|
| 81 |
col_predicha_num = "Concentración Predicha Numérica"
|
| 82 |
col_real_promedio = f"Concentración Real Promedio ({unidad_medida})"
|
| 83 |
col_desviacion = f"Desviación Estándar ({unidad_medida})"
|
|
@@ -97,10 +94,10 @@ def generar_graficos(df_valid, n_replicas, unidad_medida, estilo_grafico):
|
|
| 97 |
|
| 98 |
# Definir estilos de gráficos
|
| 99 |
estilos = {
|
| 100 |
-
"Estilo 1": {"color_puntos": "blue", "color_linea": "green", "color_error": "lightgray"},
|
| 101 |
-
"Estilo 2": {"color_puntos": "red", "color_linea": "orange", "color_error": "pink"},
|
| 102 |
-
"Estilo 3": {"color_puntos": "purple", "color_linea": "cyan", "color_error": "gray"},
|
| 103 |
-
"Estilo 4": {"color_puntos": "black", "color_linea": "yellow", "color_error": "darkgray"}
|
| 104 |
}
|
| 105 |
|
| 106 |
estilo = estilos.get(estilo_grafico, estilos["Estilo 1"])
|
|
@@ -108,48 +105,52 @@ def generar_graficos(df_valid, n_replicas, unidad_medida, estilo_grafico):
|
|
| 108 |
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
|
| 109 |
|
| 110 |
# Gráfico de dispersión con línea de regresión
|
| 111 |
-
if
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
|
|
|
| 133 |
|
| 134 |
# Línea de ajuste
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
|
|
|
|
|
|
| 142 |
|
| 143 |
# Línea ideal
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
|
|
|
| 153 |
|
| 154 |
ax1.set_title('Correlación entre Concentración Predicha y Real', fontsize=14)
|
| 155 |
ax1.set_xlabel('Concentración Predicha', fontsize=12)
|
|
@@ -175,7 +176,7 @@ def generar_graficos(df_valid, n_replicas, unidad_medida, estilo_grafico):
|
|
| 175 |
residuos,
|
| 176 |
color=estilo["color_puntos"],
|
| 177 |
s=100,
|
| 178 |
-
marker=
|
| 179 |
label='Residuos'
|
| 180 |
)
|
| 181 |
|
|
@@ -261,7 +262,7 @@ Fecha: {datetime.now().strftime('%d/%m/%Y %H:%M')}
|
|
| 261 |
"""
|
| 262 |
return informe, evaluacion['estado']
|
| 263 |
|
| 264 |
-
def actualizar_analisis(df, n_replicas, unidad_medida
|
| 265 |
if df is None or df.empty:
|
| 266 |
return "Error en los datos", None, "No se pueden generar análisis", df
|
| 267 |
|
|
@@ -284,11 +285,36 @@ def actualizar_analisis(df, n_replicas, unidad_medida, estilo_grafico):
|
|
| 284 |
slope, intercept, r_value, p_value, std_err = stats.linregress(df_valid[col_predicha_num], df_valid[col_real_promedio])
|
| 285 |
df_valid['Ajuste Lineal'] = intercept + slope * df_valid[col_predicha_num]
|
| 286 |
|
| 287 |
-
|
|
|
|
| 288 |
informe, estado = generar_informe_completo(df_valid, n_replicas, unidad_medida)
|
| 289 |
|
| 290 |
return estado, fig, informe, df
|
| 291 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 292 |
def exportar_informe_word(df_valid, informe_md, unidad_medida):
|
| 293 |
# Crear documento Word
|
| 294 |
doc = docx.Document()
|
|
@@ -534,13 +560,6 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
|
|
| 534 |
ejemplo_od_btn = gr.Button("📋 Cargar Ejemplo OD", variant="secondary")
|
| 535 |
sinteticos_btn = gr.Button("🧪 Generar Datos Sintéticos", variant="secondary")
|
| 536 |
|
| 537 |
-
with gr.Row():
|
| 538 |
-
estilo_grafico_dropdown = gr.Dropdown(
|
| 539 |
-
choices=["Estilo 1", "Estilo 2", "Estilo 3", "Estilo 4"],
|
| 540 |
-
value="Estilo 1",
|
| 541 |
-
label="Estilo del Gráfico"
|
| 542 |
-
)
|
| 543 |
-
|
| 544 |
tabla_output = gr.DataFrame(
|
| 545 |
wrap=True,
|
| 546 |
label="Tabla de Datos",
|
|
@@ -553,6 +572,17 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
|
|
| 553 |
graficos_output = gr.Plot(label="Gráficos de Análisis")
|
| 554 |
informe_output = gr.Markdown(elem_id="informe_output")
|
| 555 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 556 |
with gr.Row():
|
| 557 |
copiar_btn = gr.Button("📋 Copiar Informe", variant="secondary")
|
| 558 |
exportar_word_btn = gr.Button("💾 Exportar Informe Word", variant="primary")
|
|
@@ -568,10 +598,17 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
|
|
| 568 |
# Evento al presionar el botón Calcular
|
| 569 |
calcular_btn.click(
|
| 570 |
fn=actualizar_analisis,
|
| 571 |
-
inputs=[tabla_output, replicas_slider, unidad_input
|
| 572 |
outputs=output_components
|
| 573 |
)
|
| 574 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 575 |
# Evento para limpiar datos
|
| 576 |
limpiar_btn.click(
|
| 577 |
fn=limpiar_datos,
|
|
@@ -674,7 +711,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
|
|
| 674 |
df = generar_tabla(7, 2000000, "UFC", n_replicas)
|
| 675 |
# Valores reales de ejemplo
|
| 676 |
df[f"Concentración Real 1 (UFC)"] = [2000000, 1600000, 1200000, 800000, 400000, 200000, 100000]
|
| 677 |
-
estado, fig, informe, df = actualizar_analisis(df, n_replicas, "UFC"
|
| 678 |
return (
|
| 679 |
2000000,
|
| 680 |
"UFC",
|
|
|
|
| 49 |
df = df.copy()
|
| 50 |
# Ajustar decimales en todas las columnas numéricas
|
| 51 |
for col in df.columns:
|
| 52 |
+
try:
|
| 53 |
+
df[col] = pd.to_numeric(df[col], errors='ignore')
|
| 54 |
df[col] = df[col].round(decimales)
|
| 55 |
+
except:
|
| 56 |
+
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
return df
|
| 58 |
|
| 59 |
def calcular_promedio_desviacion(df, n_replicas, unidad_medida):
|
|
|
|
| 74 |
|
| 75 |
return df
|
| 76 |
|
| 77 |
+
def generar_graficos(df_valid, n_replicas, unidad_medida, estilo_grafico, mostrar_linea_ajuste, mostrar_linea_ideal, mostrar_puntos):
|
| 78 |
col_predicha_num = "Concentración Predicha Numérica"
|
| 79 |
col_real_promedio = f"Concentración Real Promedio ({unidad_medida})"
|
| 80 |
col_desviacion = f"Desviación Estándar ({unidad_medida})"
|
|
|
|
| 94 |
|
| 95 |
# Definir estilos de gráficos
|
| 96 |
estilos = {
|
| 97 |
+
"Estilo 1": {"color_puntos": "blue", "color_linea": "green", "color_error": "lightgray", "marker": "o", "line_style": "-"},
|
| 98 |
+
"Estilo 2": {"color_puntos": "red", "color_linea": "orange", "color_error": "pink", "marker": "s", "line_style": "--"},
|
| 99 |
+
"Estilo 3": {"color_puntos": "purple", "color_linea": "cyan", "color_error": "gray", "marker": "^", "line_style": "-."},
|
| 100 |
+
"Estilo 4": {"color_puntos": "black", "color_linea": "yellow", "color_error": "darkgray", "marker": "D", "line_style": ":"}
|
| 101 |
}
|
| 102 |
|
| 103 |
estilo = estilos.get(estilo_grafico, estilos["Estilo 1"])
|
|
|
|
| 105 |
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
|
| 106 |
|
| 107 |
# Gráfico de dispersión con línea de regresión
|
| 108 |
+
if mostrar_puntos:
|
| 109 |
+
if n_replicas > 1:
|
| 110 |
+
# Incluir barras de error
|
| 111 |
+
ax1.errorbar(
|
| 112 |
+
df_valid[col_predicha_num],
|
| 113 |
+
df_valid[col_real_promedio],
|
| 114 |
+
yerr=df_valid[col_desviacion],
|
| 115 |
+
fmt=estilo["marker"],
|
| 116 |
+
color=estilo["color_puntos"],
|
| 117 |
+
ecolor=estilo["color_error"],
|
| 118 |
+
elinewidth=2,
|
| 119 |
+
capsize=3,
|
| 120 |
+
label='Datos Reales'
|
| 121 |
+
)
|
| 122 |
+
else:
|
| 123 |
+
ax1.scatter(
|
| 124 |
+
df_valid[col_predicha_num],
|
| 125 |
+
df_valid[col_real_promedio],
|
| 126 |
+
color=estilo["color_puntos"],
|
| 127 |
+
s=100,
|
| 128 |
+
label='Datos Reales',
|
| 129 |
+
marker=estilo["marker"]
|
| 130 |
+
)
|
| 131 |
|
| 132 |
# Línea de ajuste
|
| 133 |
+
if mostrar_linea_ajuste:
|
| 134 |
+
ax1.plot(
|
| 135 |
+
df_valid[col_predicha_num],
|
| 136 |
+
df_valid['Ajuste Lineal'],
|
| 137 |
+
color=estilo["color_linea"],
|
| 138 |
+
label='Ajuste Lineal',
|
| 139 |
+
linewidth=2,
|
| 140 |
+
linestyle=estilo["line_style"]
|
| 141 |
+
)
|
| 142 |
|
| 143 |
# Línea ideal
|
| 144 |
+
if mostrar_linea_ideal:
|
| 145 |
+
min_predicha = df_valid[col_predicha_num].min()
|
| 146 |
+
max_predicha = df_valid[col_predicha_num].max()
|
| 147 |
+
ax1.plot(
|
| 148 |
+
[min_predicha, max_predicha],
|
| 149 |
+
[min_predicha, max_predicha],
|
| 150 |
+
color='red',
|
| 151 |
+
linestyle='--',
|
| 152 |
+
label='Ideal'
|
| 153 |
+
)
|
| 154 |
|
| 155 |
ax1.set_title('Correlación entre Concentración Predicha y Real', fontsize=14)
|
| 156 |
ax1.set_xlabel('Concentración Predicha', fontsize=12)
|
|
|
|
| 176 |
residuos,
|
| 177 |
color=estilo["color_puntos"],
|
| 178 |
s=100,
|
| 179 |
+
marker=estilo["marker"],
|
| 180 |
label='Residuos'
|
| 181 |
)
|
| 182 |
|
|
|
|
| 262 |
"""
|
| 263 |
return informe, evaluacion['estado']
|
| 264 |
|
| 265 |
+
def actualizar_analisis(df, n_replicas, unidad_medida):
|
| 266 |
if df is None or df.empty:
|
| 267 |
return "Error en los datos", None, "No se pueden generar análisis", df
|
| 268 |
|
|
|
|
| 285 |
slope, intercept, r_value, p_value, std_err = stats.linregress(df_valid[col_predicha_num], df_valid[col_real_promedio])
|
| 286 |
df_valid['Ajuste Lineal'] = intercept + slope * df_valid[col_predicha_num]
|
| 287 |
|
| 288 |
+
# Generar gráfico con opciones predeterminadas
|
| 289 |
+
fig = generar_graficos(df_valid, n_replicas, unidad_medida, "Estilo 1", True, True, True)
|
| 290 |
informe, estado = generar_informe_completo(df_valid, n_replicas, unidad_medida)
|
| 291 |
|
| 292 |
return estado, fig, informe, df
|
| 293 |
|
| 294 |
+
def actualizar_graficos(df, n_replicas, unidad_medida, estilo_grafico, mostrar_linea_ajuste, mostrar_linea_ideal, mostrar_puntos):
|
| 295 |
+
if df is None or df.empty:
|
| 296 |
+
return None
|
| 297 |
+
|
| 298 |
+
# Asegurarse de que los cálculos estén actualizados
|
| 299 |
+
df = calcular_promedio_desviacion(df, n_replicas, unidad_medida)
|
| 300 |
+
|
| 301 |
+
col_predicha_num = "Concentración Predicha Numérica"
|
| 302 |
+
col_real_promedio = f"Concentración Real Promedio ({unidad_medida})"
|
| 303 |
+
|
| 304 |
+
# Convertir columnas a numérico
|
| 305 |
+
df[col_predicha_num] = pd.to_numeric(df[col_predicha_num], errors='coerce')
|
| 306 |
+
df[col_real_promedio] = pd.to_numeric(df[col_real_promedio], errors='coerce')
|
| 307 |
+
|
| 308 |
+
df_valid = df.dropna(subset=[col_predicha_num, col_real_promedio])
|
| 309 |
+
|
| 310 |
+
if len(df_valid) < 2:
|
| 311 |
+
return None
|
| 312 |
+
|
| 313 |
+
# Generar gráfico con opciones seleccionadas
|
| 314 |
+
fig = generar_graficos(df_valid, n_replicas, unidad_medida, estilo_grafico, mostrar_linea_ajuste, mostrar_linea_ideal, mostrar_puntos)
|
| 315 |
+
|
| 316 |
+
return fig
|
| 317 |
+
|
| 318 |
def exportar_informe_word(df_valid, informe_md, unidad_medida):
|
| 319 |
# Crear documento Word
|
| 320 |
doc = docx.Document()
|
|
|
|
| 560 |
ejemplo_od_btn = gr.Button("📋 Cargar Ejemplo OD", variant="secondary")
|
| 561 |
sinteticos_btn = gr.Button("🧪 Generar Datos Sintéticos", variant="secondary")
|
| 562 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 563 |
tabla_output = gr.DataFrame(
|
| 564 |
wrap=True,
|
| 565 |
label="Tabla de Datos",
|
|
|
|
| 572 |
graficos_output = gr.Plot(label="Gráficos de Análisis")
|
| 573 |
informe_output = gr.Markdown(elem_id="informe_output")
|
| 574 |
|
| 575 |
+
with gr.Row():
|
| 576 |
+
estilo_grafico_dropdown = gr.Dropdown(
|
| 577 |
+
choices=["Estilo 1", "Estilo 2", "Estilo 3", "Estilo 4"],
|
| 578 |
+
value="Estilo 1",
|
| 579 |
+
label="Estilo del Gráfico"
|
| 580 |
+
)
|
| 581 |
+
mostrar_linea_ajuste = gr.Checkbox(value=True, label="Mostrar Línea de Ajuste")
|
| 582 |
+
mostrar_linea_ideal = gr.Checkbox(value=True, label="Mostrar Línea Ideal")
|
| 583 |
+
mostrar_puntos = gr.Checkbox(value=True, label="Mostrar Puntos")
|
| 584 |
+
graficar_btn = gr.Button("📊 Graficar", variant="primary")
|
| 585 |
+
|
| 586 |
with gr.Row():
|
| 587 |
copiar_btn = gr.Button("📋 Copiar Informe", variant="secondary")
|
| 588 |
exportar_word_btn = gr.Button("💾 Exportar Informe Word", variant="primary")
|
|
|
|
| 598 |
# Evento al presionar el botón Calcular
|
| 599 |
calcular_btn.click(
|
| 600 |
fn=actualizar_analisis,
|
| 601 |
+
inputs=[tabla_output, replicas_slider, unidad_input],
|
| 602 |
outputs=output_components
|
| 603 |
)
|
| 604 |
|
| 605 |
+
# Evento para graficar con opciones seleccionadas
|
| 606 |
+
graficar_btn.click(
|
| 607 |
+
fn=actualizar_graficos,
|
| 608 |
+
inputs=[tabla_output, replicas_slider, unidad_input, estilo_grafico_dropdown, mostrar_linea_ajuste, mostrar_linea_ideal, mostrar_puntos],
|
| 609 |
+
outputs=graficos_output
|
| 610 |
+
)
|
| 611 |
+
|
| 612 |
# Evento para limpiar datos
|
| 613 |
limpiar_btn.click(
|
| 614 |
fn=limpiar_datos,
|
|
|
|
| 711 |
df = generar_tabla(7, 2000000, "UFC", n_replicas)
|
| 712 |
# Valores reales de ejemplo
|
| 713 |
df[f"Concentración Real 1 (UFC)"] = [2000000, 1600000, 1200000, 800000, 400000, 200000, 100000]
|
| 714 |
+
estado, fig, informe, df = actualizar_analisis(df, n_replicas, "UFC")
|
| 715 |
return (
|
| 716 |
2000000,
|
| 717 |
"UFC",
|