Update app.py
Browse files
app.py
CHANGED
@@ -10,7 +10,7 @@ from docx.shared import Inches, Pt
|
|
10 |
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
|
11 |
import os
|
12 |
|
13 |
-
def generar_tabla(n_filas, concentracion_inicial, unidad_medida):
|
14 |
valores_base = [1.00, 0.80, 0.60, 0.40, 0.20, 0.10, 0.05]
|
15 |
|
16 |
if n_filas <= 7:
|
@@ -37,7 +37,17 @@ def generar_tabla(n_filas, concentracion_inicial, unidad_medida):
|
|
37 |
lambda x: concentracion_inicial / x
|
38 |
)
|
39 |
df[f"Concentraci贸n Predicha ({unidad_medida})"] = df["Concentraci贸n Predicha Num茅rica"].round(0).astype(str)
|
40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
|
42 |
return df
|
43 |
|
@@ -55,30 +65,36 @@ def ajustar_decimales_evento(df, decimales):
|
|
55 |
|
56 |
return df
|
57 |
|
58 |
-
def
|
59 |
-
|
60 |
-
|
|
|
|
|
|
|
|
|
61 |
|
62 |
-
#
|
63 |
-
|
64 |
-
datos_sinteticos = valores_predichos + np.random.normal(0, desviacion_std, size=len(valores_predichos))
|
65 |
-
datos_sinteticos = np.maximum(0, datos_sinteticos) # Asegurar que no haya valores negativos
|
66 |
-
datos_sinteticos = np.round(datos_sinteticos, 2)
|
67 |
|
68 |
-
|
|
|
|
|
|
|
69 |
|
70 |
return df
|
71 |
|
72 |
-
def generar_graficos(df_valid):
|
73 |
col_predicha_num = "Concentraci贸n Predicha Num茅rica"
|
74 |
-
|
|
|
75 |
|
76 |
# Convertir a num茅rico
|
77 |
df_valid[col_predicha_num] = df_valid[col_predicha_num].astype(float)
|
78 |
-
df_valid[
|
|
|
79 |
|
80 |
# Calcular regresi贸n lineal
|
81 |
-
slope, intercept, r_value, p_value, std_err = stats.linregress(df_valid[col_predicha_num], df_valid[
|
82 |
df_valid['Ajuste Lineal'] = intercept + slope * df_valid[col_predicha_num]
|
83 |
|
84 |
# Configurar estilos
|
@@ -88,16 +104,30 @@ def generar_graficos(df_valid):
|
|
88 |
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
|
89 |
|
90 |
# Gr谩fico de dispersi贸n con l铆nea de regresi贸n
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
|
102 |
# L铆nea de ajuste
|
103 |
sns.lineplot(
|
@@ -122,7 +152,7 @@ def generar_graficos(df_valid):
|
|
122 |
|
123 |
ax1.set_title('Correlaci贸n entre Concentraci贸n Predicha y Real', fontsize=14)
|
124 |
ax1.set_xlabel('Concentraci贸n Predicha', fontsize=12)
|
125 |
-
ax1.set_ylabel('Concentraci贸n Real', fontsize=12)
|
126 |
|
127 |
# A帽adir ecuaci贸n y R虏 en el gr谩fico
|
128 |
ax1.annotate(
|
@@ -138,7 +168,7 @@ def generar_graficos(df_valid):
|
|
138 |
ax1.legend(loc='lower right', fontsize=10)
|
139 |
|
140 |
# Gr谩fico de residuos
|
141 |
-
residuos = df_valid[
|
142 |
sns.scatterplot(
|
143 |
data=df_valid,
|
144 |
x=col_predicha_num,
|
@@ -188,20 +218,20 @@ def evaluar_calidad_calibracion(df_valid, r_squared, rmse, cv_percent):
|
|
188 |
|
189 |
return evaluacion
|
190 |
|
191 |
-
def generar_informe_completo(df_valid):
|
192 |
"""Generar un informe completo en formato markdown"""
|
193 |
col_predicha_num = "Concentraci贸n Predicha Num茅rica"
|
194 |
-
|
195 |
|
196 |
# Convertir a num茅rico
|
197 |
df_valid[col_predicha_num] = df_valid[col_predicha_num].astype(float)
|
198 |
-
df_valid[
|
199 |
|
200 |
# Calcular estad铆sticas
|
201 |
-
slope, intercept, r_value, p_value, std_err = stats.linregress(df_valid[col_predicha_num], df_valid[
|
202 |
r_squared = r_value ** 2
|
203 |
-
rmse = np.sqrt(((df_valid[
|
204 |
-
cv = (df_valid[
|
205 |
|
206 |
# Evaluar calidad
|
207 |
evaluacion = evaluar_calidad_calibracion(df_valid, r_squared, rmse, cv)
|
@@ -232,32 +262,35 @@ Fecha: {datetime.now().strftime('%d/%m/%Y %H:%M')}
|
|
232 |
"""
|
233 |
return informe, evaluacion['estado']
|
234 |
|
235 |
-
def actualizar_analisis(df):
|
236 |
if df is None or df.empty:
|
237 |
return "Error en los datos", None, "No se pueden generar an谩lisis"
|
238 |
|
239 |
col_predicha_num = "Concentraci贸n Predicha Num茅rica"
|
240 |
-
|
|
|
|
|
|
|
241 |
|
242 |
# Convertir columnas a num茅rico
|
243 |
df[col_predicha_num] = pd.to_numeric(df[col_predicha_num], errors='coerce')
|
244 |
-
df[
|
245 |
|
246 |
-
df_valid = df.dropna(subset=[col_predicha_num,
|
247 |
|
248 |
if len(df_valid) < 2:
|
249 |
return "Se necesitan m谩s datos", None, "Se requieren al menos dos valores reales para el an谩lisis"
|
250 |
|
251 |
# Calcular la regresi贸n y agregar 'Ajuste Lineal'
|
252 |
-
slope, intercept, r_value, p_value, std_err = stats.linregress(df_valid[col_predicha_num], df_valid[
|
253 |
df_valid['Ajuste Lineal'] = intercept + slope * df_valid[col_predicha_num]
|
254 |
|
255 |
-
fig = generar_graficos(df_valid)
|
256 |
-
informe, estado = generar_informe_completo(df_valid)
|
257 |
|
258 |
return estado, fig, informe
|
259 |
|
260 |
-
def exportar_informe_word(df_valid, informe_md):
|
261 |
# Crear documento Word
|
262 |
doc = docx.Document()
|
263 |
|
@@ -348,34 +381,34 @@ def exportar_informe_latex(df_valid, informe_md):
|
|
348 |
f.write(informe_tex)
|
349 |
return filename
|
350 |
|
351 |
-
def exportar_word(df, informe_md):
|
352 |
df_valid = df.copy()
|
353 |
col_predicha_num = "Concentraci贸n Predicha Num茅rica"
|
354 |
-
|
355 |
|
356 |
# Convertir columnas a num茅rico
|
357 |
df_valid[col_predicha_num] = pd.to_numeric(df_valid[col_predicha_num], errors='coerce')
|
358 |
-
df_valid[
|
359 |
|
360 |
-
df_valid = df_valid.dropna(subset=[col_predicha_num,
|
361 |
|
362 |
if df_valid.empty:
|
363 |
return None
|
364 |
|
365 |
-
filename = exportar_informe_word(df_valid, informe_md)
|
366 |
|
367 |
return filename # Retornamos el nombre del archivo
|
368 |
|
369 |
def exportar_latex(df, informe_md):
|
370 |
df_valid = df.copy()
|
371 |
col_predicha_num = "Concentraci贸n Predicha Num茅rica"
|
372 |
-
|
373 |
|
374 |
# Convertir columnas a num茅rico
|
375 |
df_valid[col_predicha_num] = pd.to_numeric(df_valid[col_predicha_num], errors='coerce')
|
376 |
-
df_valid[
|
377 |
|
378 |
-
df_valid = df_valid.dropna(subset=[col_predicha_num,
|
379 |
|
380 |
if df_valid.empty:
|
381 |
return None
|
@@ -385,20 +418,28 @@ def exportar_latex(df, informe_md):
|
|
385 |
return filename # Retornamos el nombre del archivo
|
386 |
|
387 |
# Funciones de ejemplo
|
388 |
-
def cargar_ejemplo_ufc():
|
389 |
-
df = generar_tabla(7, 2000000, "UFC")
|
390 |
-
|
391 |
-
|
|
|
|
|
|
|
|
|
392 |
return 2000000, "UFC", 7, df
|
393 |
|
394 |
-
def cargar_ejemplo_od():
|
395 |
-
df = generar_tabla(7, 1.0, "OD")
|
396 |
-
|
397 |
-
|
|
|
|
|
|
|
|
|
398 |
return 1.0, "OD", 7, df
|
399 |
|
400 |
-
def limpiar_datos():
|
401 |
-
df = generar_tabla(7, 2000000, "UFC")
|
402 |
return (
|
403 |
2000000, # Concentraci贸n Inicial
|
404 |
"UFC", # Unidad de Medida
|
@@ -409,27 +450,37 @@ def limpiar_datos():
|
|
409 |
"" # Informe Output
|
410 |
)
|
411 |
|
412 |
-
def generar_datos_sinteticos_evento(df):
|
413 |
df = df.copy()
|
414 |
col_predicha_num = "Concentraci贸n Predicha Num茅rica"
|
415 |
-
|
416 |
-
|
417 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
418 |
return df
|
419 |
|
420 |
-
def actualizar_tabla_evento(df, n_filas, concentracion, unidad):
|
421 |
# Actualizar tabla sin borrar "Concentraci贸n Real"
|
422 |
-
df_new = generar_tabla(n_filas, concentracion, unidad)
|
423 |
|
424 |
# Mapear columnas
|
425 |
-
col_real_new = [col for col in df_new.columns if 'Concentraci贸n Real' in col]
|
426 |
-
col_real_old = [col for col in df.columns if 'Concentraci贸n Real' in col]
|
427 |
|
428 |
# Reemplazar valores existentes en "Concentraci贸n Real"
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
|
|
433 |
|
434 |
return df_new
|
435 |
|
@@ -466,6 +517,13 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
|
|
466 |
step=1,
|
467 |
label="N煤mero de Decimales"
|
468 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
469 |
|
470 |
with gr.Row():
|
471 |
calcular_btn = gr.Button("馃攧 Calcular", variant="primary")
|
@@ -479,11 +537,11 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
|
|
479 |
|
480 |
tabla_output = gr.DataFrame(
|
481 |
row_count=(1, "dynamic"),
|
482 |
-
col_count=(6, "
|
483 |
wrap=True,
|
484 |
label="Tabla de Datos",
|
485 |
interactive=True,
|
486 |
-
datatype=
|
487 |
type="pandas",
|
488 |
)
|
489 |
|
@@ -507,32 +565,34 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
|
|
507 |
# Evento al presionar el bot贸n Calcular
|
508 |
calcular_btn.click(
|
509 |
fn=actualizar_analisis,
|
510 |
-
inputs=tabla_output,
|
511 |
outputs=output_components
|
512 |
)
|
513 |
|
514 |
# Evento para limpiar datos
|
515 |
limpiar_btn.click(
|
516 |
fn=limpiar_datos,
|
517 |
-
inputs=[],
|
518 |
outputs=[concentracion_input, unidad_input, filas_slider, tabla_output, estado_output, graficos_output, informe_output]
|
519 |
)
|
520 |
|
521 |
# Eventos de los botones de ejemplo
|
522 |
ejemplo_ufc_btn.click(
|
523 |
fn=cargar_ejemplo_ufc,
|
|
|
524 |
outputs=[concentracion_input, unidad_input, filas_slider, tabla_output]
|
525 |
)
|
526 |
|
527 |
ejemplo_od_btn.click(
|
528 |
fn=cargar_ejemplo_od,
|
|
|
529 |
outputs=[concentracion_input, unidad_input, filas_slider, tabla_output]
|
530 |
)
|
531 |
|
532 |
# Evento para generar datos sint茅ticos
|
533 |
sinteticos_btn.click(
|
534 |
fn=generar_datos_sinteticos_evento,
|
535 |
-
inputs=tabla_output,
|
536 |
outputs=tabla_output
|
537 |
)
|
538 |
|
@@ -544,21 +604,30 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
|
|
544 |
)
|
545 |
|
546 |
# Actualizar tabla al cambiar los par谩metros (sin borrar "Concentraci贸n Real")
|
|
|
|
|
|
|
547 |
concentracion_input.change(
|
548 |
-
fn=
|
549 |
-
inputs=[tabla_output, filas_slider, concentracion_input, unidad_input],
|
550 |
outputs=tabla_output
|
551 |
)
|
552 |
|
553 |
unidad_input.change(
|
554 |
-
fn=
|
555 |
-
inputs=[tabla_output, filas_slider, concentracion_input, unidad_input],
|
556 |
outputs=tabla_output
|
557 |
)
|
558 |
|
559 |
filas_slider.change(
|
560 |
-
fn=
|
561 |
-
inputs=[tabla_output, filas_slider, concentracion_input, unidad_input],
|
|
|
|
|
|
|
|
|
|
|
|
|
562 |
outputs=tabla_output
|
563 |
)
|
564 |
|
@@ -586,7 +655,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
|
|
586 |
# Eventos de exportar informes
|
587 |
exportar_word_btn.click(
|
588 |
fn=exportar_word,
|
589 |
-
inputs=[tabla_output, informe_output],
|
590 |
outputs=exportar_word_file
|
591 |
)
|
592 |
|
@@ -598,10 +667,11 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
|
|
598 |
|
599 |
# Inicializar la interfaz con el ejemplo base
|
600 |
def iniciar_con_ejemplo():
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
|
|
605 |
return (
|
606 |
2000000,
|
607 |
"UFC",
|
|
|
10 |
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
|
11 |
import os
|
12 |
|
13 |
+
def generar_tabla(n_filas, concentracion_inicial, unidad_medida, n_replicas):
|
14 |
valores_base = [1.00, 0.80, 0.60, 0.40, 0.20, 0.10, 0.05]
|
15 |
|
16 |
if n_filas <= 7:
|
|
|
37 |
lambda x: concentracion_inicial / x
|
38 |
)
|
39 |
df[f"Concentraci贸n Predicha ({unidad_medida})"] = df["Concentraci贸n Predicha Num茅rica"].round(0).astype(str)
|
40 |
+
|
41 |
+
# A帽adir columnas para las r茅plicas de "Concentraci贸n Real"
|
42 |
+
for i in range(1, n_replicas + 1):
|
43 |
+
df[f"Concentraci贸n Real {i} ({unidad_medida})"] = None
|
44 |
+
|
45 |
+
# A帽adir columnas para promedio y desviaci贸n est谩ndar si hay m谩s de una r茅plica
|
46 |
+
if n_replicas > 1:
|
47 |
+
df[f"Concentraci贸n Real Promedio ({unidad_medida})"] = None
|
48 |
+
df[f"Desviaci贸n Est谩ndar ({unidad_medida})"] = None
|
49 |
+
else:
|
50 |
+
df[f"Concentraci贸n Real Promedio ({unidad_medida})"] = None
|
51 |
|
52 |
return df
|
53 |
|
|
|
65 |
|
66 |
return df
|
67 |
|
68 |
+
def calcular_promedio_desviacion(df, n_replicas, unidad_medida):
|
69 |
+
df = df.copy()
|
70 |
+
# Obtener las columnas de r茅plicas
|
71 |
+
col_replicas = [f"Concentraci贸n Real {i} ({unidad_medida})" for i in range(1, n_replicas + 1)]
|
72 |
+
# Convertir a num茅rico
|
73 |
+
for col in col_replicas:
|
74 |
+
df[col] = pd.to_numeric(df[col], errors='coerce')
|
75 |
|
76 |
+
# Calcular el promedio y la desviaci贸n est谩ndar
|
77 |
+
df[f"Concentraci贸n Real Promedio ({unidad_medida})"] = df[col_replicas].mean(axis=1)
|
|
|
|
|
|
|
78 |
|
79 |
+
if n_replicas > 1:
|
80 |
+
df[f"Desviaci贸n Est谩ndar ({unidad_medida})"] = df[col_replicas].std(ddof=1, axis=1)
|
81 |
+
else:
|
82 |
+
df[f"Desviaci贸n Est谩ndar ({unidad_medida})"] = 0.0
|
83 |
|
84 |
return df
|
85 |
|
86 |
+
def generar_graficos(df_valid, n_replicas, unidad_medida):
|
87 |
col_predicha_num = "Concentraci贸n Predicha Num茅rica"
|
88 |
+
col_real_promedio = f"Concentraci贸n Real Promedio ({unidad_medida})"
|
89 |
+
col_desviacion = f"Desviaci贸n Est谩ndar ({unidad_medida})"
|
90 |
|
91 |
# Convertir a num茅rico
|
92 |
df_valid[col_predicha_num] = df_valid[col_predicha_num].astype(float)
|
93 |
+
df_valid[col_real_promedio] = df_valid[col_real_promedio].astype(float)
|
94 |
+
df_valid[col_desviacion] = df_valid[col_desviacion].astype(float)
|
95 |
|
96 |
# Calcular regresi贸n lineal
|
97 |
+
slope, intercept, r_value, p_value, std_err = stats.linregress(df_valid[col_predicha_num], df_valid[col_real_promedio])
|
98 |
df_valid['Ajuste Lineal'] = intercept + slope * df_valid[col_predicha_num]
|
99 |
|
100 |
# Configurar estilos
|
|
|
104 |
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
|
105 |
|
106 |
# Gr谩fico de dispersi贸n con l铆nea de regresi贸n
|
107 |
+
if n_replicas > 1:
|
108 |
+
# Incluir barras de error
|
109 |
+
ax1.errorbar(
|
110 |
+
df_valid[col_predicha_num],
|
111 |
+
df_valid[col_real_promedio],
|
112 |
+
yerr=df_valid[col_desviacion],
|
113 |
+
fmt='o',
|
114 |
+
color='blue',
|
115 |
+
ecolor='lightgray',
|
116 |
+
elinewidth=3,
|
117 |
+
capsize=0,
|
118 |
+
label='Datos Reales'
|
119 |
+
)
|
120 |
+
else:
|
121 |
+
sns.scatterplot(
|
122 |
+
data=df_valid,
|
123 |
+
x=col_predicha_num,
|
124 |
+
y=col_real_promedio,
|
125 |
+
ax=ax1,
|
126 |
+
color='blue',
|
127 |
+
s=100,
|
128 |
+
label='Datos Reales',
|
129 |
+
marker='o'
|
130 |
+
)
|
131 |
|
132 |
# L铆nea de ajuste
|
133 |
sns.lineplot(
|
|
|
152 |
|
153 |
ax1.set_title('Correlaci贸n entre Concentraci贸n Predicha y Real', fontsize=14)
|
154 |
ax1.set_xlabel('Concentraci贸n Predicha', fontsize=12)
|
155 |
+
ax1.set_ylabel('Concentraci贸n Real Promedio', fontsize=12)
|
156 |
|
157 |
# A帽adir ecuaci贸n y R虏 en el gr谩fico
|
158 |
ax1.annotate(
|
|
|
168 |
ax1.legend(loc='lower right', fontsize=10)
|
169 |
|
170 |
# Gr谩fico de residuos
|
171 |
+
residuos = df_valid[col_real_promedio] - df_valid['Ajuste Lineal']
|
172 |
sns.scatterplot(
|
173 |
data=df_valid,
|
174 |
x=col_predicha_num,
|
|
|
218 |
|
219 |
return evaluacion
|
220 |
|
221 |
+
def generar_informe_completo(df_valid, n_replicas, unidad_medida):
|
222 |
"""Generar un informe completo en formato markdown"""
|
223 |
col_predicha_num = "Concentraci贸n Predicha Num茅rica"
|
224 |
+
col_real_promedio = f"Concentraci贸n Real Promedio ({unidad_medida})"
|
225 |
|
226 |
# Convertir a num茅rico
|
227 |
df_valid[col_predicha_num] = df_valid[col_predicha_num].astype(float)
|
228 |
+
df_valid[col_real_promedio] = df_valid[col_real_promedio].astype(float)
|
229 |
|
230 |
# Calcular estad铆sticas
|
231 |
+
slope, intercept, r_value, p_value, std_err = stats.linregress(df_valid[col_predicha_num], df_valid[col_real_promedio])
|
232 |
r_squared = r_value ** 2
|
233 |
+
rmse = np.sqrt(((df_valid[col_real_promedio] - (intercept + slope * df_valid[col_predicha_num])) ** 2).mean())
|
234 |
+
cv = (df_valid[col_real_promedio].std() / df_valid[col_real_promedio].mean()) * 100 # CV de los valores reales
|
235 |
|
236 |
# Evaluar calidad
|
237 |
evaluacion = evaluar_calidad_calibracion(df_valid, r_squared, rmse, cv)
|
|
|
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"
|
268 |
|
269 |
col_predicha_num = "Concentraci贸n Predicha Num茅rica"
|
270 |
+
col_real_promedio = f"Concentraci贸n Real Promedio ({unidad_medida})"
|
271 |
+
|
272 |
+
# Calcular promedio y desviaci贸n est谩ndar
|
273 |
+
df = calcular_promedio_desviacion(df, n_replicas, unidad_medida)
|
274 |
|
275 |
# Convertir columnas a num茅rico
|
276 |
df[col_predicha_num] = pd.to_numeric(df[col_predicha_num], errors='coerce')
|
277 |
+
df[col_real_promedio] = pd.to_numeric(df[col_real_promedio], errors='coerce')
|
278 |
|
279 |
+
df_valid = df.dropna(subset=[col_predicha_num, col_real_promedio])
|
280 |
|
281 |
if len(df_valid) < 2:
|
282 |
return "Se necesitan m谩s datos", None, "Se requieren al menos dos valores reales para el an谩lisis"
|
283 |
|
284 |
# Calcular la regresi贸n y agregar 'Ajuste Lineal'
|
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 |
+
fig = generar_graficos(df_valid, n_replicas, unidad_medida)
|
289 |
+
informe, estado = generar_informe_completo(df_valid, n_replicas, unidad_medida)
|
290 |
|
291 |
return estado, fig, informe
|
292 |
|
293 |
+
def exportar_informe_word(df_valid, informe_md, unidad_medida):
|
294 |
# Crear documento Word
|
295 |
doc = docx.Document()
|
296 |
|
|
|
381 |
f.write(informe_tex)
|
382 |
return filename
|
383 |
|
384 |
+
def exportar_word(df, informe_md, unidad_medida):
|
385 |
df_valid = df.copy()
|
386 |
col_predicha_num = "Concentraci贸n Predicha Num茅rica"
|
387 |
+
col_real_promedio = f"Concentraci贸n Real Promedio ({unidad_medida})"
|
388 |
|
389 |
# Convertir columnas a num茅rico
|
390 |
df_valid[col_predicha_num] = pd.to_numeric(df_valid[col_predicha_num], errors='coerce')
|
391 |
+
df_valid[col_real_promedio] = pd.to_numeric(df_valid[col_real_promedio], errors='coerce')
|
392 |
|
393 |
+
df_valid = df_valid.dropna(subset=[col_predicha_num, col_real_promedio])
|
394 |
|
395 |
if df_valid.empty:
|
396 |
return None
|
397 |
|
398 |
+
filename = exportar_informe_word(df_valid, informe_md, unidad_medida)
|
399 |
|
400 |
return filename # Retornamos el nombre del archivo
|
401 |
|
402 |
def exportar_latex(df, informe_md):
|
403 |
df_valid = df.copy()
|
404 |
col_predicha_num = "Concentraci贸n Predicha Num茅rica"
|
405 |
+
col_real_promedio = [col for col in df_valid.columns if 'Real Promedio' in col][0]
|
406 |
|
407 |
# Convertir columnas a num茅rico
|
408 |
df_valid[col_predicha_num] = pd.to_numeric(df_valid[col_predicha_num], errors='coerce')
|
409 |
+
df_valid[col_real_promedio] = pd.to_numeric(df_valid[col_real_promedio], errors='coerce')
|
410 |
|
411 |
+
df_valid = df_valid.dropna(subset=[col_predicha_num, col_real_promedio])
|
412 |
|
413 |
if df_valid.empty:
|
414 |
return None
|
|
|
418 |
return filename # Retornamos el nombre del archivo
|
419 |
|
420 |
# Funciones de ejemplo
|
421 |
+
def cargar_ejemplo_ufc(n_replicas):
|
422 |
+
df = generar_tabla(7, 2000000, "UFC", n_replicas)
|
423 |
+
# Valores reales de ejemplo
|
424 |
+
for i in range(1, n_replicas + 1):
|
425 |
+
valores_reales = [2000000 - (i - 1) * 10000, 1600000 - (i - 1) * 8000, 1200000 - (i - 1) * 6000,
|
426 |
+
800000 - (i - 1) * 4000, 400000 - (i - 1) * 2000, 200000 - (i - 1) * 1000,
|
427 |
+
100000 - (i - 1) * 500]
|
428 |
+
df[f"Concentraci贸n Real {i} (UFC)"] = valores_reales
|
429 |
return 2000000, "UFC", 7, df
|
430 |
|
431 |
+
def cargar_ejemplo_od(n_replicas):
|
432 |
+
df = generar_tabla(7, 1.0, "OD", n_replicas)
|
433 |
+
# Valores reales de ejemplo
|
434 |
+
for i in range(1, n_replicas + 1):
|
435 |
+
valores_reales = [1.00 - (i - 1) * 0.05, 0.80 - (i - 1) * 0.04, 0.60 - (i - 1) * 0.03,
|
436 |
+
0.40 - (i - 1) * 0.02, 0.20 - (i - 1) * 0.01, 0.10 - (i - 1) * 0.005,
|
437 |
+
0.05 - (i - 1) * 0.002]
|
438 |
+
df[f"Concentraci贸n Real {i} (OD)"] = valores_reales
|
439 |
return 1.0, "OD", 7, df
|
440 |
|
441 |
+
def limpiar_datos(n_replicas):
|
442 |
+
df = generar_tabla(7, 2000000, "UFC", n_replicas)
|
443 |
return (
|
444 |
2000000, # Concentraci贸n Inicial
|
445 |
"UFC", # Unidad de Medida
|
|
|
450 |
"" # Informe Output
|
451 |
)
|
452 |
|
453 |
+
def generar_datos_sinteticos_evento(df, n_replicas, unidad_medida):
|
454 |
df = df.copy()
|
455 |
col_predicha_num = "Concentraci贸n Predicha Num茅rica"
|
456 |
+
|
457 |
+
# Generar datos sint茅ticos para cada r茅plica
|
458 |
+
for i in range(1, n_replicas + 1):
|
459 |
+
col_real = f"Concentraci贸n Real {i} ({unidad_medida})"
|
460 |
+
df[col_predicha_num] = pd.to_numeric(df[col_predicha_num], errors='coerce')
|
461 |
+
desviacion_std = 0.05 * df[col_predicha_num].mean() # 5% de la media como desviaci贸n est谩ndar
|
462 |
+
valores_predichos = df[col_predicha_num].astype(float).values
|
463 |
+
datos_sinteticos = valores_predichos + np.random.normal(0, desviacion_std, size=len(valores_predichos))
|
464 |
+
datos_sinteticos = np.maximum(0, datos_sinteticos) # Asegurar que no haya valores negativos
|
465 |
+
datos_sinteticos = np.round(datos_sinteticos, 2)
|
466 |
+
df[col_real] = datos_sinteticos
|
467 |
+
|
468 |
return df
|
469 |
|
470 |
+
def actualizar_tabla_evento(df, n_filas, concentracion, unidad, n_replicas):
|
471 |
# Actualizar tabla sin borrar "Concentraci贸n Real"
|
472 |
+
df_new = generar_tabla(n_filas, concentracion, unidad, n_replicas)
|
473 |
|
474 |
# Mapear columnas
|
475 |
+
col_real_new = [col for col in df_new.columns if 'Concentraci贸n Real' in col]
|
476 |
+
col_real_old = [col for col in df.columns if 'Concentraci贸n Real' in col]
|
477 |
|
478 |
# Reemplazar valores existentes en "Concentraci贸n Real"
|
479 |
+
for col_new, col_old in zip(col_real_new, col_real_old):
|
480 |
+
df_new[col_new] = None
|
481 |
+
for idx in df_new.index:
|
482 |
+
if idx in df.index:
|
483 |
+
df_new.at[idx, col_new] = df.at[idx, col_old]
|
484 |
|
485 |
return df_new
|
486 |
|
|
|
517 |
step=1,
|
518 |
label="N煤mero de Decimales"
|
519 |
)
|
520 |
+
replicas_slider = gr.Slider(
|
521 |
+
minimum=1,
|
522 |
+
maximum=5,
|
523 |
+
value=1,
|
524 |
+
step=1,
|
525 |
+
label="N煤mero de R茅plicas"
|
526 |
+
)
|
527 |
|
528 |
with gr.Row():
|
529 |
calcular_btn = gr.Button("馃攧 Calcular", variant="primary")
|
|
|
537 |
|
538 |
tabla_output = gr.DataFrame(
|
539 |
row_count=(1, "dynamic"),
|
540 |
+
col_count=(6, "dynamic"),
|
541 |
wrap=True,
|
542 |
label="Tabla de Datos",
|
543 |
interactive=True,
|
544 |
+
datatype="auto",
|
545 |
type="pandas",
|
546 |
)
|
547 |
|
|
|
565 |
# Evento al presionar el bot贸n Calcular
|
566 |
calcular_btn.click(
|
567 |
fn=actualizar_analisis,
|
568 |
+
inputs=[tabla_output, replicas_slider, unidad_input],
|
569 |
outputs=output_components
|
570 |
)
|
571 |
|
572 |
# Evento para limpiar datos
|
573 |
limpiar_btn.click(
|
574 |
fn=limpiar_datos,
|
575 |
+
inputs=[replicas_slider],
|
576 |
outputs=[concentracion_input, unidad_input, filas_slider, tabla_output, estado_output, graficos_output, informe_output]
|
577 |
)
|
578 |
|
579 |
# Eventos de los botones de ejemplo
|
580 |
ejemplo_ufc_btn.click(
|
581 |
fn=cargar_ejemplo_ufc,
|
582 |
+
inputs=[replicas_slider],
|
583 |
outputs=[concentracion_input, unidad_input, filas_slider, tabla_output]
|
584 |
)
|
585 |
|
586 |
ejemplo_od_btn.click(
|
587 |
fn=cargar_ejemplo_od,
|
588 |
+
inputs=[replicas_slider],
|
589 |
outputs=[concentracion_input, unidad_input, filas_slider, tabla_output]
|
590 |
)
|
591 |
|
592 |
# Evento para generar datos sint茅ticos
|
593 |
sinteticos_btn.click(
|
594 |
fn=generar_datos_sinteticos_evento,
|
595 |
+
inputs=[tabla_output, replicas_slider, unidad_input],
|
596 |
outputs=tabla_output
|
597 |
)
|
598 |
|
|
|
604 |
)
|
605 |
|
606 |
# Actualizar tabla al cambiar los par谩metros (sin borrar "Concentraci贸n Real")
|
607 |
+
def actualizar_tabla_wrapper(df, filas, conc, unidad, replicas):
|
608 |
+
return actualizar_tabla_evento(df, filas, conc, unidad, replicas)
|
609 |
+
|
610 |
concentracion_input.change(
|
611 |
+
fn=actualizar_tabla_wrapper,
|
612 |
+
inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
|
613 |
outputs=tabla_output
|
614 |
)
|
615 |
|
616 |
unidad_input.change(
|
617 |
+
fn=actualizar_tabla_wrapper,
|
618 |
+
inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
|
619 |
outputs=tabla_output
|
620 |
)
|
621 |
|
622 |
filas_slider.change(
|
623 |
+
fn=actualizar_tabla_wrapper,
|
624 |
+
inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
|
625 |
+
outputs=tabla_output
|
626 |
+
)
|
627 |
+
|
628 |
+
replicas_slider.change(
|
629 |
+
fn=actualizar_tabla_wrapper,
|
630 |
+
inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
|
631 |
outputs=tabla_output
|
632 |
)
|
633 |
|
|
|
655 |
# Eventos de exportar informes
|
656 |
exportar_word_btn.click(
|
657 |
fn=exportar_word,
|
658 |
+
inputs=[tabla_output, informe_output, unidad_input],
|
659 |
outputs=exportar_word_file
|
660 |
)
|
661 |
|
|
|
667 |
|
668 |
# Inicializar la interfaz con el ejemplo base
|
669 |
def iniciar_con_ejemplo():
|
670 |
+
n_replicas = 1
|
671 |
+
df = generar_tabla(7, 2000000, "UFC", n_replicas)
|
672 |
+
# Valores reales de ejemplo
|
673 |
+
df[f"Concentraci贸n Real 1 (UFC)"] = [2000000, 1600000, 1200000, 800000, 400000, 200000, 100000]
|
674 |
+
estado, fig, informe = actualizar_analisis(df, n_replicas, "UFC")
|
675 |
return (
|
676 |
2000000,
|
677 |
"UFC",
|