C2MV commited on
Commit
5ad6a7e
verified
1 Parent(s): 2bcdcdd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +402 -42
app.py CHANGED
@@ -11,11 +11,11 @@ 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:
17
  solucion_inoculo = valores_base[:n_filas]
18
- agua = [round(1 - x, 2) for x in solucion_inoculo]
19
  else:
20
  solucion_inoculo = valores_base.copy()
21
  ultimo_valor = valores_base[-1]
@@ -32,11 +32,11 @@ def generar_tabla(n_filas, concentracion_inicial, unidad_medida, n_replicas):
32
  df = pd.DataFrame(data)
33
 
34
  nombre_columna = f"Soluci贸n de in贸culo ({concentracion_inicial} {unidad_medida})"
35
- df["Factor de Diluci贸n"] = df[nombre_columna].apply(lambda x: round(1 / x, 2))
36
  df["Concentraci贸n Predicha Num茅rica"] = df["Factor de Diluci贸n"].apply(
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):
@@ -56,7 +56,7 @@ def ajustar_decimales_evento(df, decimales):
56
  pass
57
  return df
58
 
59
- def calcular_promedio_desviacion(df, n_replicas, unidad_medida):
60
  df = df.copy()
61
  # Obtener las columnas de r茅plicas
62
  col_replicas = [f"Concentraci贸n Real {i} ({unidad_medida})" for i in range(1, n_replicas + 1)]
@@ -72,6 +72,10 @@ def calcular_promedio_desviacion(df, n_replicas, unidad_medida):
72
  else:
73
  df[f"Desviaci贸n Est谩ndar ({unidad_medida})"] = 0.0
74
 
 
 
 
 
75
  return df
76
 
77
  def generar_graficos(df_valid, n_replicas, unidad_medida, palette_puntos, estilo_puntos,
@@ -163,7 +167,7 @@ def generar_graficos(df_valid, n_replicas, unidad_medida, palette_puntos, estilo
163
 
164
  # A帽adir ecuaci贸n y R虏 en el gr谩fico
165
  ax1.annotate(
166
- f'y = {intercept:.2f} + {slope:.2f}x\n$R^2$ = {r_value**2:.4f}',
167
  xy=(0.05, 0.95),
168
  xycoords='axes fraction',
169
  fontsize=12,
@@ -267,12 +271,18 @@ Fecha: {datetime.now().strftime('%d/%m/%Y %H:%M')}
267
  """
268
  return informe, evaluacion['estado']
269
 
270
- def actualizar_analisis(df, n_replicas, unidad_medida):
271
  if df is None or df.empty:
272
  return "Error en los datos", None, "No se pueden generar an谩lisis", df
273
 
 
 
 
 
 
 
274
  # Calcular promedio y desviaci贸n est谩ndar dependiendo de las r茅plicas
275
- df = calcular_promedio_desviacion(df, n_replicas, unidad_medida)
276
 
277
  col_predicha_num = "Concentraci贸n Predicha Num茅rica"
278
  col_real_promedio = f"Concentraci贸n Real Promedio ({unidad_medida})"
@@ -283,6 +293,12 @@ def actualizar_analisis(df, n_replicas, unidad_medida):
283
 
284
  df_valid = df.dropna(subset=[col_predicha_num, col_real_promedio])
285
 
 
 
 
 
 
 
286
  if len(df_valid) < 2:
287
  return "Se necesitan m谩s datos", None, "Se requieren al menos dos valores reales para el an谩lisis", df
288
 
@@ -297,7 +313,9 @@ def actualizar_analisis(df, n_replicas, unidad_medida):
297
  palette_linea_ajuste='muted', estilo_linea_ajuste='-',
298
  palette_linea_ideal='bright', estilo_linea_ideal='--',
299
  palette_barras_error='pastel',
300
- mostrar_linea_ajuste=True, mostrar_linea_ideal=True, mostrar_puntos=True
 
 
301
  )
302
  informe, estado = generar_informe_completo(df_valid, n_replicas, unidad_medida)
303
 
@@ -308,12 +326,13 @@ def actualizar_graficos(df, n_replicas, unidad_medida,
308
  palette_linea_ajuste, estilo_linea_ajuste,
309
  palette_linea_ideal, estilo_linea_ideal,
310
  palette_barras_error,
311
- mostrar_linea_ajuste, mostrar_linea_ideal, mostrar_puntos):
 
312
  if df is None or df.empty:
313
  return None
314
 
315
  # Asegurarse de que los c谩lculos est茅n actualizados
316
- df = calcular_promedio_desviacion(df, n_replicas, unidad_medida)
317
 
318
  col_predicha_num = "Concentraci贸n Predicha Num茅rica"
319
  col_real_promedio = f"Concentraci贸n Real Promedio ({unidad_medida})"
@@ -324,6 +343,18 @@ def actualizar_graficos(df, n_replicas, unidad_medida,
324
 
325
  df_valid = df.dropna(subset=[col_predicha_num, col_real_promedio])
326
 
 
 
 
 
 
 
 
 
 
 
 
 
327
  if len(df_valid) < 2:
328
  return None
329
 
@@ -430,7 +461,7 @@ def exportar_informe_latex(df_valid, informe_md):
430
  f.write(informe_tex)
431
  return filename
432
 
433
- def exportar_word(df, informe_md, unidad_medida):
434
  df_valid = df.copy()
435
  col_predicha_num = "Concentraci贸n Predicha Num茅rica"
436
  col_real_promedio = f"Concentraci贸n Real Promedio ({unidad_medida})"
@@ -441,6 +472,18 @@ def exportar_word(df, informe_md, unidad_medida):
441
 
442
  df_valid = df_valid.dropna(subset=[col_predicha_num, col_real_promedio])
443
 
 
 
 
 
 
 
 
 
 
 
 
 
444
  if df_valid.empty:
445
  return None
446
 
@@ -448,7 +491,7 @@ def exportar_word(df, informe_md, unidad_medida):
448
 
449
  return filename # Retornamos el nombre del archivo
450
 
451
- def exportar_latex(df, informe_md):
452
  df_valid = df.copy()
453
  col_predicha_num = "Concentraci贸n Predicha Num茅rica"
454
  col_real_promedio = [col for col in df_valid.columns if 'Real Promedio' in col][0]
@@ -459,6 +502,18 @@ def exportar_latex(df, informe_md):
459
 
460
  df_valid = df_valid.dropna(subset=[col_predicha_num, col_real_promedio])
461
 
 
 
 
 
 
 
 
 
 
 
 
 
462
  if df_valid.empty:
463
  return None
464
 
@@ -466,7 +521,6 @@ def exportar_latex(df, informe_md):
466
 
467
  return filename # Retornamos el nombre del archivo
468
 
469
- # Funciones de ejemplo
470
  def cargar_ejemplo_ufc(n_replicas):
471
  df = generar_tabla(7, 2000000, "UFC", n_replicas)
472
  # Valores reales de ejemplo
@@ -478,14 +532,14 @@ def cargar_ejemplo_ufc(n_replicas):
478
  return 2000000, "UFC", 7, df
479
 
480
  def cargar_ejemplo_od(n_replicas):
481
- df = generar_tabla(7, 1.0, "OD", n_replicas)
482
  # Valores reales de ejemplo
483
  for i in range(1, n_replicas + 1):
484
- valores_reales = [1.00 - (i - 1) * 0.05, 0.80 - (i - 1) * 0.04, 0.60 - (i - 1) * 0.03,
485
- 0.40 - (i - 1) * 0.02, 0.20 - (i - 1) * 0.01, 0.10 - (i - 1) * 0.005,
486
- 0.05 - (i - 1) * 0.002]
487
  df[f"Concentraci贸n Real {i} (OD)"] = valores_reales
488
- return 1.0, "OD", 7, df
489
 
490
  def limpiar_datos(n_replicas):
491
  df = generar_tabla(7, 2000000, "UFC", n_replicas)
@@ -511,12 +565,12 @@ def generar_datos_sinteticos_evento(df, n_replicas, unidad_medida):
511
  valores_predichos = df[col_predicha_num].astype(float).values
512
  datos_sinteticos = valores_predichos + np.random.normal(0, desviacion_std, size=len(valores_predichos))
513
  datos_sinteticos = np.maximum(0, datos_sinteticos) # Asegurar que no haya valores negativos
514
- datos_sinteticos = np.round(datos_sinteticos, 2)
515
  df[col_real] = datos_sinteticos
516
 
517
  return df
518
 
519
- def actualizar_tabla_evento(df, n_filas, concentracion, unidad, n_replicas):
520
  # Actualizar tabla sin borrar "Concentraci贸n Real"
521
  df_new = generar_tabla(n_filas, concentracion, unidad, n_replicas)
522
 
@@ -531,13 +585,16 @@ def actualizar_tabla_evento(df, n_filas, concentracion, unidad, n_replicas):
531
  if idx in df.index:
532
  df_new.at[idx, col_new] = df.at[idx, col_old]
533
 
 
 
 
534
  return df_new
535
 
536
  def cargar_excel(file):
537
  # Leer el archivo Excel
538
  df = pd.read_excel(file.name, sheet_name=None)
539
 
540
- # Verificar que el archivo tenga al menos dos pesta帽as
541
  if len(df) < 2:
542
  return "El archivo debe tener al menos dos pesta帽as.", None, None, None, None, None, None
543
 
@@ -558,6 +615,164 @@ def cargar_excel(file):
558
 
559
  return concentracion_inicial, unidad_medida, n_filas, n_replicas, df_base, "", None, ""
560
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
561
  # Interfaz Gradio
562
  with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
563
  gr.Markdown("""
@@ -587,7 +802,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
587
  decimales_slider = gr.Slider(
588
  minimum=0,
589
  maximum=5,
590
- value=0,
591
  step=1,
592
  label="N煤mero de Decimales"
593
  )
@@ -621,6 +836,13 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
621
  estado_output = gr.Textbox(label="Estado", interactive=False)
622
  graficos_output = gr.Plot(label="Gr谩ficos de An谩lisis")
623
 
 
 
 
 
 
 
 
624
  # Opciones y botones debajo del gr谩fico
625
  with gr.Row():
626
  # Paletas de colores disponibles en Seaborn
@@ -664,7 +886,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
664
  label="Paleta Barras de Error"
665
  )
666
  mostrar_linea_ajuste = gr.Checkbox(value=True, label="Mostrar L铆nea de Ajuste")
667
- mostrar_linea_ideal = gr.Checkbox(value=True, label="Mostrar L铆nea Ideal")
668
  mostrar_puntos = gr.Checkbox(value=True, label="Mostrar Puntos")
669
  graficar_btn = gr.Button("馃搳 Graficar", variant="primary")
670
 
@@ -680,15 +902,104 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
680
  # Informe al final
681
  informe_output = gr.Markdown(elem_id="informe_output")
682
 
683
- # Eventos
684
- input_components = [tabla_output]
685
- output_components = [estado_output, graficos_output, informe_output, tabla_output]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
686
 
687
  # Evento al presionar el bot贸n Calcular
688
  calcular_btn.click(
689
  fn=actualizar_analisis,
690
- inputs=[tabla_output, replicas_slider, unidad_input],
691
- outputs=output_components
692
  )
693
 
694
  # Evento para graficar con opciones seleccionadas
@@ -700,11 +1011,35 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
700
  palette_linea_ajuste_dropdown, estilo_linea_ajuste_dropdown,
701
  palette_linea_ideal_dropdown, estilo_linea_ideal_dropdown,
702
  palette_barras_error_dropdown,
703
- mostrar_linea_ajuste, mostrar_linea_ideal, mostrar_puntos
 
704
  ],
705
  outputs=graficos_output
706
  )
707
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
708
  # Evento para limpiar datos
709
  limpiar_btn.click(
710
  fn=limpiar_datos,
@@ -747,34 +1082,38 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
747
  )
748
 
749
  # Actualizar tabla al cambiar los par谩metros (sin borrar "Concentraci贸n Real")
750
- def actualizar_tabla_wrapper(df, filas, conc, unidad, replicas):
751
- return actualizar_tabla_evento(df, filas, conc, unidad, replicas)
752
 
753
  concentracion_input.change(
754
  fn=actualizar_tabla_wrapper,
755
- inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
756
  outputs=tabla_output
757
  )
758
 
759
  unidad_input.change(
760
  fn=actualizar_tabla_wrapper,
761
- inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
762
  outputs=tabla_output
763
  )
764
 
765
  filas_slider.change(
766
  fn=actualizar_tabla_wrapper,
767
- inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
768
  outputs=tabla_output
769
  )
770
 
771
  replicas_slider.change(
772
  fn=actualizar_tabla_wrapper,
773
- inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
774
  outputs=tabla_output
775
  )
776
 
777
- # No agregamos un evento para decimales_slider.change, para evitar borrar la columna "Concentraci贸n Real"
 
 
 
 
778
 
779
  # Evento de copiar informe utilizando JavaScript
780
  copiar_btn.click(
@@ -798,13 +1137,13 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
798
  # Eventos de exportar informes
799
  exportar_word_btn.click(
800
  fn=exportar_word,
801
- inputs=[tabla_output, informe_output, unidad_input],
802
  outputs=exportar_word_file
803
  )
804
 
805
  exportar_latex_btn.click(
806
  fn=exportar_latex,
807
- inputs=[tabla_output, informe_output],
808
  outputs=exportar_latex_file
809
  )
810
 
@@ -814,7 +1153,10 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
814
  df = generar_tabla(7, 2000000, "UFC", n_replicas)
815
  # Valores reales de ejemplo
816
  df[f"Concentraci贸n Real 1 (UFC)"] = [2000000, 1600000, 1200000, 800000, 400000, 200000, 100000]
817
- estado, fig, informe, df = actualizar_analisis(df, n_replicas, "UFC")
 
 
 
818
  return (
819
  2000000,
820
  "UFC",
@@ -822,12 +1164,30 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
822
  df,
823
  estado,
824
  fig,
825
- informe
 
 
826
  )
827
 
828
  interfaz.load(
829
  fn=iniciar_con_ejemplo,
830
- outputs=[concentracion_input, unidad_input, filas_slider, tabla_output, estado_output, graficos_output, informe_output]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
831
  )
832
 
833
  # Lanzar la interfaz
 
11
  import os
12
 
13
  def generar_tabla(n_filas, concentracion_inicial, unidad_medida, n_replicas):
14
+ valores_base = [1.000, 0.800, 0.600, 0.400, 0.200, 0.100, 0.050]
15
 
16
  if n_filas <= 7:
17
  solucion_inoculo = valores_base[:n_filas]
18
+ agua = [round(1 - x, 3) for x in solucion_inoculo]
19
  else:
20
  solucion_inoculo = valores_base.copy()
21
  ultimo_valor = valores_base[-1]
 
32
  df = pd.DataFrame(data)
33
 
34
  nombre_columna = f"Soluci贸n de in贸culo ({concentracion_inicial} {unidad_medida})"
35
+ df["Factor de Diluci贸n"] = df[nombre_columna].apply(lambda x: round(1 / x, 3))
36
  df["Concentraci贸n Predicha Num茅rica"] = df["Factor de Diluci贸n"].apply(
37
  lambda x: concentracion_inicial / x
38
  )
39
+ df[f"Concentraci贸n Predicha ({unidad_medida})"] = df["Concentraci贸n Predicha Num茅rica"].round(3).astype(str)
40
 
41
  # A帽adir columnas para las r茅plicas de "Concentraci贸n Real"
42
  for i in range(1, n_replicas + 1):
 
56
  pass
57
  return df
58
 
59
+ def calcular_promedio_desviacion(df, n_replicas, unidad_medida, decimales):
60
  df = df.copy()
61
  # Obtener las columnas de r茅plicas
62
  col_replicas = [f"Concentraci贸n Real {i} ({unidad_medida})" for i in range(1, n_replicas + 1)]
 
72
  else:
73
  df[f"Desviaci贸n Est谩ndar ({unidad_medida})"] = 0.0
74
 
75
+ # Redondear al n煤mero de decimales especificado
76
+ df[f"Concentraci贸n Real Promedio ({unidad_medida})"] = df[f"Concentraci贸n Real Promedio ({unidad_medida})"].round(decimales)
77
+ df[f"Desviaci贸n Est谩ndar ({unidad_medida})"] = df[f"Desviaci贸n Est谩ndar ({unidad_medida})"].round(decimales)
78
+
79
  return df
80
 
81
  def generar_graficos(df_valid, n_replicas, unidad_medida, palette_puntos, estilo_puntos,
 
167
 
168
  # A帽adir ecuaci贸n y R虏 en el gr谩fico
169
  ax1.annotate(
170
+ f'y = {intercept:.3f} + {slope:.3f}x\n$R^2$ = {r_value**2:.4f}',
171
  xy=(0.05, 0.95),
172
  xycoords='axes fraction',
173
  fontsize=12,
 
271
  """
272
  return informe, evaluacion['estado']
273
 
274
+ def actualizar_analisis(df, n_replicas, unidad_medida, filas_seleccionadas, decimales):
275
  if df is None or df.empty:
276
  return "Error en los datos", None, "No se pueden generar an谩lisis", df
277
 
278
+ # Convertir filas_seleccionadas a 铆ndices
279
+ if not filas_seleccionadas:
280
+ return "Se necesitan m谩s datos", None, "No se han seleccionado filas para el an谩lisis", df
281
+
282
+ indices_seleccionados = [int(s.split(' ')[1]) - 1 for s in filas_seleccionadas]
283
+
284
  # Calcular promedio y desviaci贸n est谩ndar dependiendo de las r茅plicas
285
+ df = calcular_promedio_desviacion(df, n_replicas, unidad_medida, decimales)
286
 
287
  col_predicha_num = "Concentraci贸n Predicha Num茅rica"
288
  col_real_promedio = f"Concentraci贸n Real Promedio ({unidad_medida})"
 
293
 
294
  df_valid = df.dropna(subset=[col_predicha_num, col_real_promedio])
295
 
296
+ # Resetear el 铆ndice para asegurar que sea secuencial
297
+ df_valid.reset_index(drop=True, inplace=True)
298
+
299
+ # Filtrar filas seg煤n las seleccionadas
300
+ df_valid = df_valid.loc[indices_seleccionados]
301
+
302
  if len(df_valid) < 2:
303
  return "Se necesitan m谩s datos", None, "Se requieren al menos dos valores reales para el an谩lisis", df
304
 
 
313
  palette_linea_ajuste='muted', estilo_linea_ajuste='-',
314
  palette_linea_ideal='bright', estilo_linea_ideal='--',
315
  palette_barras_error='pastel',
316
+ mostrar_linea_ajuste=True,
317
+ mostrar_linea_ideal=False, # L铆nea Ideal desmarcada por defecto
318
+ mostrar_puntos=True
319
  )
320
  informe, estado = generar_informe_completo(df_valid, n_replicas, unidad_medida)
321
 
 
326
  palette_linea_ajuste, estilo_linea_ajuste,
327
  palette_linea_ideal, estilo_linea_ideal,
328
  palette_barras_error,
329
+ mostrar_linea_ajuste, mostrar_linea_ideal, mostrar_puntos,
330
+ filas_seleccionadas, decimales):
331
  if df is None or df.empty:
332
  return None
333
 
334
  # Asegurarse de que los c谩lculos est茅n actualizados
335
+ df = calcular_promedio_desviacion(df, n_replicas, unidad_medida, decimales)
336
 
337
  col_predicha_num = "Concentraci贸n Predicha Num茅rica"
338
  col_real_promedio = f"Concentraci贸n Real Promedio ({unidad_medida})"
 
343
 
344
  df_valid = df.dropna(subset=[col_predicha_num, col_real_promedio])
345
 
346
+ # Resetear el 铆ndice para asegurar que sea secuencial
347
+ df_valid.reset_index(drop=True, inplace=True)
348
+
349
+ # Convertir filas_seleccionadas a 铆ndices
350
+ if not filas_seleccionadas:
351
+ return None
352
+
353
+ indices_seleccionados = [int(s.split(' ')[1]) - 1 for s in filas_seleccionadas]
354
+
355
+ # Filtrar filas seg煤n las seleccionadas
356
+ df_valid = df_valid.loc[indices_seleccionados]
357
+
358
  if len(df_valid) < 2:
359
  return None
360
 
 
461
  f.write(informe_tex)
462
  return filename
463
 
464
+ def exportar_word(df, informe_md, unidad_medida, filas_seleccionadas):
465
  df_valid = df.copy()
466
  col_predicha_num = "Concentraci贸n Predicha Num茅rica"
467
  col_real_promedio = f"Concentraci贸n Real Promedio ({unidad_medida})"
 
472
 
473
  df_valid = df_valid.dropna(subset=[col_predicha_num, col_real_promedio])
474
 
475
+ # Resetear el 铆ndice
476
+ df_valid.reset_index(drop=True, inplace=True)
477
+
478
+ # Convertir filas_seleccionadas a 铆ndices
479
+ if not filas_seleccionadas:
480
+ return None
481
+
482
+ indices_seleccionados = [int(s.split(' ')[1]) - 1 for s in filas_seleccionadas]
483
+
484
+ # Filtrar filas seg煤n las seleccionadas
485
+ df_valid = df_valid.loc[indices_seleccionados]
486
+
487
  if df_valid.empty:
488
  return None
489
 
 
491
 
492
  return filename # Retornamos el nombre del archivo
493
 
494
+ def exportar_latex(df, informe_md, filas_seleccionadas):
495
  df_valid = df.copy()
496
  col_predicha_num = "Concentraci贸n Predicha Num茅rica"
497
  col_real_promedio = [col for col in df_valid.columns if 'Real Promedio' in col][0]
 
502
 
503
  df_valid = df_valid.dropna(subset=[col_predicha_num, col_real_promedio])
504
 
505
+ # Resetear el 铆ndice
506
+ df_valid.reset_index(drop=True, inplace=True)
507
+
508
+ # Convertir filas_seleccionadas a 铆ndices
509
+ if not filas_seleccionadas:
510
+ return None
511
+
512
+ indices_seleccionados = [int(s.split(' ')[1]) - 1 for s in filas_seleccionadas]
513
+
514
+ # Filtrar filas seg煤n las seleccionadas
515
+ df_valid = df_valid.loc[indices_seleccionados]
516
+
517
  if df_valid.empty:
518
  return None
519
 
 
521
 
522
  return filename # Retornamos el nombre del archivo
523
 
 
524
  def cargar_ejemplo_ufc(n_replicas):
525
  df = generar_tabla(7, 2000000, "UFC", n_replicas)
526
  # Valores reales de ejemplo
 
532
  return 2000000, "UFC", 7, df
533
 
534
  def cargar_ejemplo_od(n_replicas):
535
+ df = generar_tabla(7, 1.000, "OD", n_replicas)
536
  # Valores reales de ejemplo
537
  for i in range(1, n_replicas + 1):
538
+ valores_reales = [1.000 - (i - 1) * 0.050, 0.800 - (i - 1) * 0.040, 0.600 - (i - 1) * 0.030,
539
+ 0.400 - (i - 1) * 0.020, 0.200 - (i - 1) * 0.010, 0.100 - (i - 1) * 0.005,
540
+ 0.050 - (i - 1) * 0.002]
541
  df[f"Concentraci贸n Real {i} (OD)"] = valores_reales
542
+ return 1.000, "OD", 7, df
543
 
544
  def limpiar_datos(n_replicas):
545
  df = generar_tabla(7, 2000000, "UFC", n_replicas)
 
565
  valores_predichos = df[col_predicha_num].astype(float).values
566
  datos_sinteticos = valores_predichos + np.random.normal(0, desviacion_std, size=len(valores_predichos))
567
  datos_sinteticos = np.maximum(0, datos_sinteticos) # Asegurar que no haya valores negativos
568
+ datos_sinteticos = np.round(datos_sinteticos, 3)
569
  df[col_real] = datos_sinteticos
570
 
571
  return df
572
 
573
+ def actualizar_tabla_evento(df, n_filas, concentracion, unidad, n_replicas, decimales):
574
  # Actualizar tabla sin borrar "Concentraci贸n Real"
575
  df_new = generar_tabla(n_filas, concentracion, unidad, n_replicas)
576
 
 
585
  if idx in df.index:
586
  df_new.at[idx, col_new] = df.at[idx, col_old]
587
 
588
+ # Ajustar decimales
589
+ df_new = ajustar_decimales_evento(df_new, decimales)
590
+
591
  return df_new
592
 
593
  def cargar_excel(file):
594
  # Leer el archivo Excel
595
  df = pd.read_excel(file.name, sheet_name=None)
596
 
597
+ # Verificar que el archivo tenga al menos dos pesta帽as.
598
  if len(df) < 2:
599
  return "El archivo debe tener al menos dos pesta帽as.", None, None, None, None, None, None
600
 
 
615
 
616
  return concentracion_inicial, unidad_medida, n_filas, n_replicas, df_base, "", None, ""
617
 
618
+ def calcular_regresion_tabla_principal(df, unidad_medida, filas_seleccionadas_regresion,
619
+ palette_puntos, estilo_puntos,
620
+ palette_linea_ajuste, estilo_linea_ajuste,
621
+ mostrar_linea_ajuste, mostrar_puntos,
622
+ legend_location, decimales,
623
+ titulo_grafico_original, titulo_grafico_personalizado,
624
+ eje_x_original, eje_y_original,
625
+ eje_x_personalizado, eje_y_personalizado):
626
+ if df is None or df.empty:
627
+ return "Datos insuficientes", None, None, None
628
+
629
+ col_concentracion = "Concentraci贸n Predicha Num茅rica"
630
+ col_absorbancia = f"Concentraci贸n Real Promedio ({unidad_medida})"
631
+ col_desviacion = f"Desviaci贸n Est谩ndar ({unidad_medida})"
632
+
633
+ # Calcular promedio y desviaci贸n est谩ndar si es necesario
634
+ n_replicas = len([col for col in df.columns if 'Concentraci贸n Real' in col and 'Promedio' not in col and 'Desviaci贸n' not in col])
635
+ df = calcular_promedio_desviacion(df, n_replicas, unidad_medida, decimales)
636
+
637
+ # Convertir columnas a num茅rico
638
+ df[col_concentracion] = pd.to_numeric(df[col_concentracion], errors='coerce')
639
+ df[col_absorbancia] = pd.to_numeric(df[col_absorbancia], errors='coerce')
640
+ df[col_desviacion] = pd.to_numeric(df[col_desviacion], errors='coerce')
641
+
642
+ df_valid = df.dropna(subset=[col_concentracion, col_absorbancia])
643
+
644
+ # Resetear el 铆ndice para asegurar que sea secuencial
645
+ df_valid.reset_index(drop=True, inplace=True)
646
+
647
+ # Asegurar que el gr谩fico original tenga todos los puntos
648
+ df_original = df_valid.copy()
649
+
650
+ # Convertir filas_seleccionadas a 铆ndices
651
+ if not filas_seleccionadas_regresion:
652
+ return "Se necesitan m谩s datos", None, None, None
653
+
654
+ indices_seleccionados = [int(s.split(' ')[1]) - 1 for s in filas_seleccionadas_regresion]
655
+
656
+ # Filtrar filas seg煤n las seleccionadas para el gr谩fico personalizado
657
+ df_valid = df_valid.loc[indices_seleccionados]
658
+
659
+ if len(df_valid) < 2:
660
+ return "Se requieren al menos dos puntos para calcular la regresi贸n", None, None, None
661
+
662
+ # Calcular regresi贸n lineal para el gr谩fico personalizado
663
+ slope, intercept, r_value, p_value, std_err = stats.linregress(df_valid[col_concentracion], df_valid[col_absorbancia])
664
+
665
+ # Generar gr谩fico original (con todos los puntos)
666
+ sns.set(style="whitegrid")
667
+ fig_original, ax_original = plt.subplots(figsize=(8, 6))
668
+
669
+ ax_original.errorbar(
670
+ df_original[col_concentracion],
671
+ df_original[col_absorbancia],
672
+ yerr=df_original[col_desviacion],
673
+ fmt='o',
674
+ color='blue',
675
+ ecolor='gray',
676
+ elinewidth=1,
677
+ capsize=3,
678
+ label='Datos'
679
+ )
680
+
681
+ # Calcular regresi贸n para todos los puntos
682
+ slope_all, intercept_all, r_value_all, p_value_all, std_err_all = stats.linregress(df_original[col_concentracion], df_original[col_absorbancia])
683
+
684
+ ax_original.plot(
685
+ df_original[col_concentracion],
686
+ intercept_all + slope_all * df_original[col_concentracion],
687
+ color='red',
688
+ linestyle='-',
689
+ label='Ajuste Lineal'
690
+ )
691
+
692
+ # T铆tulo y etiquetas personalizadas para el gr谩fico original
693
+ ax_original.set_xlabel(eje_x_original if eje_x_original else 'Concentraci贸n Predicha Num茅rica')
694
+ ax_original.set_ylabel(eje_y_original if eje_y_original else f'Concentraci贸n Real Promedio ({unidad_medida})')
695
+ ax_original.set_title(titulo_grafico_original if titulo_grafico_original else 'Regresi贸n Lineal: Concentraci贸n Real vs Concentraci贸n Predicha (Original)')
696
+
697
+ # Posicionar la leyenda seg煤n la opci贸n seleccionada (por defecto 'lower right')
698
+ ax_original.legend(loc=legend_location)
699
+
700
+ # A帽adir ecuaci贸n y R虏 en el gr谩fico
701
+ ax_original.annotate(
702
+ f'y = {intercept_all:.4f} + {slope_all:.4f}x\n$R^2$ = {r_value_all**2:.4f}',
703
+ xy=(0.05, 0.95),
704
+ xycoords='axes fraction',
705
+ fontsize=12,
706
+ backgroundcolor='white',
707
+ verticalalignment='top'
708
+ )
709
+
710
+ # Generar gr谩fico personalizado
711
+ sns.set(style="whitegrid")
712
+ fig_personalizado, ax_personalizado = plt.subplots(figsize=(8, 6))
713
+
714
+ # Obtener colores de las paletas
715
+ colors_puntos = sns.color_palette(palette_puntos, as_cmap=False)
716
+ colors_linea_ajuste = sns.color_palette(palette_linea_ajuste, as_cmap=False)
717
+
718
+ color_puntos = colors_puntos[0]
719
+ color_linea_ajuste = colors_linea_ajuste[0]
720
+
721
+ if mostrar_puntos:
722
+ ax_personalizado.errorbar(
723
+ df_valid[col_concentracion],
724
+ df_valid[col_absorbancia],
725
+ yerr=df_valid[col_desviacion],
726
+ fmt=estilo_puntos,
727
+ color=color_puntos,
728
+ ecolor='gray',
729
+ elinewidth=1,
730
+ capsize=3,
731
+ label='Datos'
732
+ )
733
+
734
+ if mostrar_linea_ajuste:
735
+ ax_personalizado.plot(
736
+ df_valid[col_concentracion],
737
+ intercept + slope * df_valid[col_concentracion],
738
+ color=color_linea_ajuste,
739
+ linestyle=estilo_linea_ajuste,
740
+ label='Ajuste Lineal'
741
+ )
742
+
743
+ # T铆tulo y etiquetas personalizadas para el gr谩fico personalizado
744
+ ax_personalizado.set_xlabel(eje_x_personalizado if eje_x_personalizado else 'Concentraci贸n Predicha Num茅rica')
745
+ ax_personalizado.set_ylabel(eje_y_personalizado if eje_y_personalizado else f'Concentraci贸n Real Promedio ({unidad_medida})')
746
+ ax_personalizado.set_title(titulo_grafico_personalizado if titulo_grafico_personalizado else 'Regresi贸n Lineal Personalizada')
747
+
748
+ # Posicionar la leyenda seg煤n la opci贸n seleccionada
749
+ ax_personalizado.legend(loc=legend_location)
750
+
751
+ # A帽adir ecuaci贸n y R虏 en el gr谩fico
752
+ ax_personalizado.annotate(
753
+ f'y = {intercept:.4f} + {slope:.4f}x\n$R^2$ = {r_value**2:.4f}',
754
+ xy=(0.05, 0.95),
755
+ xycoords='axes fraction',
756
+ fontsize=12,
757
+ backgroundcolor='white',
758
+ verticalalignment='top'
759
+ )
760
+
761
+ # Crear tabla resumida
762
+ df_resumen = df_valid[[col_concentracion, col_absorbancia, col_desviacion]].copy()
763
+ df_resumen.columns = ['Concentraci贸n Predicha', 'Absorbancia Promedio', 'Desviaci贸n Est谩ndar']
764
+
765
+ return "Regresi贸n calculada exitosamente", fig_original, fig_personalizado, df_resumen
766
+
767
+ # Funci贸n corregida para actualizar las opciones de filas
768
+ def actualizar_opciones_filas(df):
769
+ if df is None or df.empty:
770
+ update = gr.update(choices=[], value=[])
771
+ else:
772
+ opciones = [f"Fila {i+1}" for i in df.index]
773
+ update = gr.update(choices=opciones, value=opciones)
774
+ return update, update
775
+
776
  # Interfaz Gradio
777
  with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
778
  gr.Markdown("""
 
802
  decimales_slider = gr.Slider(
803
  minimum=0,
804
  maximum=5,
805
+ value=3,
806
  step=1,
807
  label="N煤mero de Decimales"
808
  )
 
836
  estado_output = gr.Textbox(label="Estado", interactive=False)
837
  graficos_output = gr.Plot(label="Gr谩ficos de An谩lisis")
838
 
839
+ # Reemplazar Multiselect por CheckboxGroup
840
+ filas_seleccionadas = gr.CheckboxGroup(
841
+ label="Seleccione las filas a incluir en el an谩lisis",
842
+ choices=[],
843
+ value=[],
844
+ )
845
+
846
  # Opciones y botones debajo del gr谩fico
847
  with gr.Row():
848
  # Paletas de colores disponibles en Seaborn
 
886
  label="Paleta Barras de Error"
887
  )
888
  mostrar_linea_ajuste = gr.Checkbox(value=True, label="Mostrar L铆nea de Ajuste")
889
+ mostrar_linea_ideal = gr.Checkbox(value=False, label="Mostrar L铆nea Ideal") # Desmarcado por defecto
890
  mostrar_puntos = gr.Checkbox(value=True, label="Mostrar Puntos")
891
  graficar_btn = gr.Button("馃搳 Graficar", variant="primary")
892
 
 
902
  # Informe al final
903
  informe_output = gr.Markdown(elem_id="informe_output")
904
 
905
+ with gr.Tab("馃搱 Regresi贸n Absorbancia vs Concentraci贸n"):
906
+ gr.Markdown("## Ajuste de Regresi贸n utilizando datos de la Tabla Principal")
907
+
908
+ # Casillas para seleccionar filas
909
+ filas_seleccionadas_regresion = gr.CheckboxGroup(
910
+ label="Seleccione las filas a incluir en el an谩lisis de regresi贸n",
911
+ choices=[],
912
+ value=[],
913
+ )
914
+
915
+ # Opciones de personalizaci贸n
916
+ with gr.Row():
917
+ paletas_colores = ["deep", "muted", "pastel", "bright", "dark", "colorblind", "Set1", "Set2", "Set3"]
918
+ palette_puntos_regresion = gr.Dropdown(
919
+ choices=paletas_colores,
920
+ value="deep",
921
+ label="Paleta para Puntos"
922
+ )
923
+ estilo_puntos_regresion = gr.Dropdown(
924
+ choices=["o", "s", "^", "D", "v", "<", ">", "h", "H", "p", "*", "X", "d"],
925
+ value="o",
926
+ label="Estilo de Puntos"
927
+ )
928
+ palette_linea_ajuste_regresion = gr.Dropdown(
929
+ choices=paletas_colores,
930
+ value="muted",
931
+ label="Paleta L铆nea de Ajuste"
932
+ )
933
+ estilo_linea_ajuste_regresion = gr.Dropdown(
934
+ choices=["-", "--", "-.", ":"],
935
+ value="-",
936
+ label="Estilo L铆nea de Ajuste"
937
+ )
938
+ mostrar_linea_ajuste_regresion = gr.Checkbox(value=True, label="Mostrar L铆nea de Ajuste")
939
+ mostrar_puntos_regresion = gr.Checkbox(value=True, label="Mostrar Puntos")
940
+
941
+ with gr.Row():
942
+ legend_location_dropdown = gr.Dropdown(
943
+ choices=[
944
+ 'best', 'upper right', 'upper left', 'lower left', 'lower right',
945
+ 'right', 'center left', 'center right', 'lower center',
946
+ 'upper center', 'center'
947
+ ],
948
+ value='lower right', # Por defecto 'lower right'
949
+ label='Ubicaci贸n de la Leyenda'
950
+ )
951
+
952
+ # Campos de texto para personalizar t铆tulo y ejes
953
+ with gr.Row():
954
+ titulo_grafico_original = gr.Textbox(
955
+ label="T铆tulo del Gr谩fico Original",
956
+ placeholder="Regresi贸n Lineal: Concentraci贸n Real vs Concentraci贸n Predicha (Original)"
957
+ )
958
+ titulo_grafico_personalizado = gr.Textbox(
959
+ label="T铆tulo del Gr谩fico Personalizado",
960
+ placeholder="Regresi贸n Lineal Personalizada"
961
+ )
962
+
963
+ with gr.Row():
964
+ eje_x_original = gr.Textbox(
965
+ label="Etiqueta del Eje X (Gr谩fico Original)",
966
+ placeholder="Concentraci贸n Predicha Num茅rica"
967
+ )
968
+ eje_y_original = gr.Textbox(
969
+ label="Etiqueta del Eje Y (Gr谩fico Original)",
970
+ placeholder=f"Concentraci贸n Real Promedio ({unidad_input.value})"
971
+ )
972
+
973
+ with gr.Row():
974
+ eje_x_personalizado = gr.Textbox(
975
+ label="Etiqueta del Eje X (Gr谩fico Personalizado)",
976
+ placeholder="Concentraci贸n Predicha Num茅rica"
977
+ )
978
+ eje_y_personalizado = gr.Textbox(
979
+ label="Etiqueta del Eje Y (Gr谩fico Personalizado)",
980
+ placeholder=f"Concentraci贸n Real Promedio ({unidad_input.value})"
981
+ )
982
+
983
+ calcular_regresion_btn = gr.Button("Calcular Regresi贸n")
984
+
985
+ # Salidas
986
+ estado_regresion_output = gr.Textbox(label="Estado de la Regresi贸n", interactive=False)
987
+ grafico_original_output = gr.Plot(label="Gr谩fico Original")
988
+ grafico_personalizado_output = gr.Plot(label="Gr谩fico Personalizado")
989
+ tabla_resumen_output = gr.DataFrame(label="Tabla Resumida")
990
+
991
+ # Eventos para actualizar las opciones de filas
992
+ tabla_output.change(
993
+ fn=actualizar_opciones_filas,
994
+ inputs=[tabla_output],
995
+ outputs=[filas_seleccionadas, filas_seleccionadas_regresion]
996
+ )
997
 
998
  # Evento al presionar el bot贸n Calcular
999
  calcular_btn.click(
1000
  fn=actualizar_analisis,
1001
+ inputs=[tabla_output, replicas_slider, unidad_input, filas_seleccionadas, decimales_slider],
1002
+ outputs=[estado_output, graficos_output, informe_output, tabla_output]
1003
  )
1004
 
1005
  # Evento para graficar con opciones seleccionadas
 
1011
  palette_linea_ajuste_dropdown, estilo_linea_ajuste_dropdown,
1012
  palette_linea_ideal_dropdown, estilo_linea_ideal_dropdown,
1013
  palette_barras_error_dropdown,
1014
+ mostrar_linea_ajuste, mostrar_linea_ideal, mostrar_puntos,
1015
+ filas_seleccionadas, decimales_slider
1016
  ],
1017
  outputs=graficos_output
1018
  )
1019
 
1020
+ # Asegurar que la l铆nea ideal est茅 desmarcada por defecto
1021
+ def resetear_linea_ideal():
1022
+ return gr.update(value=False)
1023
+
1024
+ # Desmarcar 'Mostrar L铆nea Ideal' en eventos de botones
1025
+ calcular_btn.click(
1026
+ fn=resetear_linea_ideal,
1027
+ outputs=mostrar_linea_ideal
1028
+ )
1029
+ limpiar_btn.click(
1030
+ fn=resetear_linea_ideal,
1031
+ outputs=mostrar_linea_ideal
1032
+ )
1033
+ ajustar_decimales_btn.click(
1034
+ fn=resetear_linea_ideal,
1035
+ outputs=mostrar_linea_ideal
1036
+ )
1037
+ sinteticos_btn.click(
1038
+ fn=resetear_linea_ideal,
1039
+ outputs=mostrar_linea_ideal
1040
+ )
1041
+
1042
+ # Eventos de los botones adicionales, como limpiar, cargar ejemplos, ajustar decimales, etc.
1043
  # Evento para limpiar datos
1044
  limpiar_btn.click(
1045
  fn=limpiar_datos,
 
1082
  )
1083
 
1084
  # Actualizar tabla al cambiar los par谩metros (sin borrar "Concentraci贸n Real")
1085
+ def actualizar_tabla_wrapper(df, filas, conc, unidad, replicas, decimales):
1086
+ return actualizar_tabla_evento(df, filas, conc, unidad, replicas, decimales)
1087
 
1088
  concentracion_input.change(
1089
  fn=actualizar_tabla_wrapper,
1090
+ inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider, decimales_slider],
1091
  outputs=tabla_output
1092
  )
1093
 
1094
  unidad_input.change(
1095
  fn=actualizar_tabla_wrapper,
1096
+ inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider, decimales_slider],
1097
  outputs=tabla_output
1098
  )
1099
 
1100
  filas_slider.change(
1101
  fn=actualizar_tabla_wrapper,
1102
+ inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider, decimales_slider],
1103
  outputs=tabla_output
1104
  )
1105
 
1106
  replicas_slider.change(
1107
  fn=actualizar_tabla_wrapper,
1108
+ inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider, decimales_slider],
1109
  outputs=tabla_output
1110
  )
1111
 
1112
+ decimales_slider.change(
1113
+ fn=ajustar_decimales_evento,
1114
+ inputs=[tabla_output, decimales_slider],
1115
+ outputs=tabla_output
1116
+ )
1117
 
1118
  # Evento de copiar informe utilizando JavaScript
1119
  copiar_btn.click(
 
1137
  # Eventos de exportar informes
1138
  exportar_word_btn.click(
1139
  fn=exportar_word,
1140
+ inputs=[tabla_output, informe_output, unidad_input, filas_seleccionadas],
1141
  outputs=exportar_word_file
1142
  )
1143
 
1144
  exportar_latex_btn.click(
1145
  fn=exportar_latex,
1146
+ inputs=[tabla_output, informe_output, filas_seleccionadas],
1147
  outputs=exportar_latex_file
1148
  )
1149
 
 
1153
  df = generar_tabla(7, 2000000, "UFC", n_replicas)
1154
  # Valores reales de ejemplo
1155
  df[f"Concentraci贸n Real 1 (UFC)"] = [2000000, 1600000, 1200000, 800000, 400000, 200000, 100000]
1156
+ # Calcular promedio y desviaci贸n est谩ndar
1157
+ df = calcular_promedio_desviacion(df, n_replicas, "UFC", 3)
1158
+ filas_seleccionadas_inicial = [f"Fila {i+1}" for i in df.index]
1159
+ estado, fig, informe, df = actualizar_analisis(df, n_replicas, "UFC", filas_seleccionadas_inicial, 3)
1160
  return (
1161
  2000000,
1162
  "UFC",
 
1164
  df,
1165
  estado,
1166
  fig,
1167
+ informe,
1168
+ filas_seleccionadas_inicial,
1169
+ 3 # N煤mero de decimales
1170
  )
1171
 
1172
  interfaz.load(
1173
  fn=iniciar_con_ejemplo,
1174
+ outputs=[concentracion_input, unidad_input, filas_slider, tabla_output, estado_output, graficos_output, informe_output, filas_seleccionadas, decimales_slider]
1175
+ )
1176
+
1177
+ # Evento al presionar el bot贸n de calcular regresi贸n
1178
+ calcular_regresion_btn.click(
1179
+ fn=calcular_regresion_tabla_principal,
1180
+ inputs=[
1181
+ tabla_output, unidad_input, filas_seleccionadas_regresion,
1182
+ palette_puntos_regresion, estilo_puntos_regresion,
1183
+ palette_linea_ajuste_regresion, estilo_linea_ajuste_regresion,
1184
+ mostrar_linea_ajuste_regresion, mostrar_puntos_regresion,
1185
+ legend_location_dropdown, decimales_slider,
1186
+ titulo_grafico_original, titulo_grafico_personalizado,
1187
+ eje_x_original, eje_y_original,
1188
+ eje_x_personalizado, eje_y_personalizado
1189
+ ],
1190
+ outputs=[estado_regresion_output, grafico_original_output, grafico_personalizado_output, tabla_resumen_output]
1191
  )
1192
 
1193
  # Lanzar la interfaz