C2MV commited on
Commit
9a0cdae
verified
1 Parent(s): 9a4cc26

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +162 -243
app.py CHANGED
@@ -95,7 +95,7 @@ def generar_graficos(df_valid, n_replicas, unidad_medida, palette_puntos, estilo
95
  sns.set(style="whitegrid")
96
  plt.rcParams.update({'figure.autolayout': True})
97
 
98
- fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 5)) # Tama帽o ajustado a (10, 5)
99
 
100
  # Obtener colores de las paletas
101
  colors_puntos = sns.color_palette(palette_puntos, as_cmap=False)
@@ -267,82 +267,52 @@ Fecha: {datetime.now().strftime('%d/%m/%Y %H:%M')}
267
  """
268
  return informe, evaluacion['estado']
269
 
270
- def generar_lista_puntos(df, unidad_medida):
271
- """Genera una lista de descripciones de puntos para el CheckboxGroup"""
272
- lista = []
273
- for idx, row in df.iterrows():
274
- predicha = row.get(f"Concentraci贸n Predicha ({unidad_medida})", "N/A")
275
- real_promedio = row.get(f"Concentraci贸n Real Promedio ({unidad_medida})", "N/A")
276
- descripcion = f"Punto {idx + 1}: Predicha={predicha}, Real Promedio={real_promedio}"
277
- lista.append(descripcion)
278
- return lista
279
-
280
- def evaluar_puntos_seleccionados(df, puntos_seleccionados, unidad_medida):
281
- if not puntos_seleccionados:
282
- return df # Si no se selecciona ning煤n punto, retornar el DataFrame completo
283
-
284
- # Crear una lista de descripciones para comparaci贸n
285
- lista_puntos = generar_lista_puntos(df, unidad_medida)
286
-
287
- # Filtrar el DataFrame para incluir solo los puntos seleccionados
288
- indices_seleccionados = [lista_puntos.index(punto) for punto in puntos_seleccionados if punto in lista_puntos]
289
- df_filtrado = df.iloc[indices_seleccionados].reset_index(drop=True)
290
- return df_filtrado
291
-
292
- def recalcular(df, n_replicas, unidad_medida, puntos_seleccionados,
293
- palette_puntos, estilo_puntos,
294
- palette_linea_ajuste, estilo_linea_ajuste,
295
- palette_linea_ideal, estilo_linea_ideal,
296
- palette_barras_error,
297
- mostrar_linea_ajuste, mostrar_linea_ideal, mostrar_puntos):
298
  if df is None or df.empty:
299
- return "Error en los datos", None, "No se pueden generar an谩lisis", df, gr.CheckboxGroup.update(choices=[], value=[])
300
 
301
- # Calcular promedio y desviaci贸n est谩ndar
302
  df = calcular_promedio_desviacion(df, n_replicas, unidad_medida)
303
 
304
- # Filtrar los puntos seleccionados
305
- df_filtrado = evaluar_puntos_seleccionados(df, puntos_seleccionados, unidad_medida)
306
-
307
  col_predicha_num = "Concentraci贸n Predicha Num茅rica"
308
  col_real_promedio = f"Concentraci贸n Real Promedio ({unidad_medida})"
309
 
310
  # Convertir columnas a num茅rico
311
- df_filtrado[col_predicha_num] = pd.to_numeric(df_filtrado[col_predicha_num], errors='coerce')
312
- df_filtrado[col_real_promedio] = pd.to_numeric(df_filtrado[col_real_promedio], errors='coerce')
313
 
314
- df_valid = df_filtrado.dropna(subset=[col_predicha_num, col_real_promedio])
315
 
316
  if len(df_valid) < 2:
317
- return "Se necesitan m谩s datos", None, "Se requieren al menos dos valores reales para el an谩lisis", df, gr.CheckboxGroup.update(choices=[], value=[])
318
 
319
  # Calcular la regresi贸n y agregar 'Ajuste Lineal'
320
  slope, intercept, r_value, p_value, std_err = stats.linregress(df_valid[col_predicha_num], df_valid[col_real_promedio])
321
  df_valid['Ajuste Lineal'] = intercept + slope * df_valid[col_predicha_num]
322
 
323
- # Generar gr谩fico con opciones seleccionadas
324
  fig = generar_graficos(
325
  df_valid, n_replicas, unidad_medida,
326
- palette_puntos, estilo_puntos,
327
- palette_linea_ajuste, estilo_linea_ajuste,
328
- palette_linea_ideal, estilo_linea_ideal,
329
- palette_barras_error,
330
- mostrar_linea_ajuste, mostrar_linea_ideal, mostrar_puntos
331
  )
332
-
333
- # Generar informe
334
  informe, estado = generar_informe_completo(df_valid, n_replicas, unidad_medida)
335
 
336
- # Generar lista de puntos para selecci贸n
337
- lista_puntos = generar_lista_puntos(df, unidad_medida)
338
 
339
- return estado, fig, informe, df, gr.CheckboxGroup.update(choices=lista_puntos, value=puntos_seleccionados)
340
-
341
- def actualizar_analisis(df, n_replicas, unidad_medida):
 
 
 
342
  if df is None or df.empty:
343
- return "Error en los datos", None, "No se pueden generar an谩lisis", df
344
 
345
- # Calcular promedio y desviaci贸n est谩ndar dependiendo de las r茅plicas
346
  df = calcular_promedio_desviacion(df, n_replicas, unidad_medida)
347
 
348
  col_predicha_num = "Concentraci贸n Predicha Num茅rica"
@@ -355,29 +325,19 @@ def actualizar_analisis(df, n_replicas, unidad_medida):
355
  df_valid = df.dropna(subset=[col_predicha_num, col_real_promedio])
356
 
357
  if len(df_valid) < 2:
358
- return "Se necesitan m谩s datos", None, "Se requieren al menos dos valores reales para el an谩lisis", df
359
-
360
- # Calcular la regresi贸n y agregar 'Ajuste Lineal'
361
- slope, intercept, r_value, p_value, std_err = stats.linregress(df_valid[col_predicha_num], df_valid[col_real_promedio])
362
- df_valid['Ajuste Lineal'] = intercept + slope * df_valid[col_predicha_num]
363
 
364
- # Generar gr谩fico con opciones predeterminadas
365
  fig = generar_graficos(
366
  df_valid, n_replicas, unidad_medida,
367
- palette_puntos='deep', estilo_puntos='o',
368
- palette_linea_ajuste='muted', estilo_linea_ajuste='-',
369
- palette_linea_ideal='bright', estilo_linea_ideal='--',
370
- palette_barras_error='pastel',
371
- mostrar_linea_ajuste=True, mostrar_linea_ideal=True, mostrar_puntos=True
372
  )
373
 
374
- # Generar informe
375
- informe, estado = generar_informe_completo(df_valid, n_replicas, unidad_medida)
376
-
377
- # Generar lista de puntos para selecci贸n
378
- lista_puntos = generar_lista_puntos(df, unidad_medida)
379
-
380
- return estado, fig, informe, df, gr.CheckboxGroup.update(choices=lista_puntos, value=lista_puntos)
381
 
382
  def exportar_informe_word(df_valid, informe_md, unidad_medida):
383
  # Crear documento Word
@@ -407,10 +367,7 @@ def exportar_informe_word(df_valid, informe_md, unidad_medida):
407
  leyenda = doc.add_paragraph('Figura 1. Gr谩fico de calibraci贸n.')
408
  leyenda_format = leyenda.paragraph_format
409
  leyenda_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
410
- if 'Caption' in doc.styles:
411
- leyenda.style = doc.styles['Caption']
412
- else:
413
- leyenda.style = doc.styles['Normal'] # Fallback si no existe 'Caption'
414
 
415
  # Agregar contenido del informe
416
  doc.add_heading('Resumen Estad铆stico', level=1)
@@ -491,10 +448,10 @@ def exportar_word(df, informe_md, unidad_medida):
491
 
492
  return filename # Retornamos el nombre del archivo
493
 
494
- def exportar_latex(df, informe_md, unidad_medida):
495
  df_valid = df.copy()
496
  col_predicha_num = "Concentraci贸n Predicha Num茅rica"
497
- col_real_promedio = f"Concentraci贸n Real Promedio ({unidad_medida})"
498
 
499
  # Convertir columnas a num茅rico
500
  df_valid[col_predicha_num] = pd.to_numeric(df_valid[col_predicha_num], errors='coerce')
@@ -636,20 +593,9 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
636
 
637
  with gr.Tab("馃搳 An谩lisis y Reporte"):
638
  estado_output = gr.Textbox(label="Estado", interactive=False)
639
- with gr.Row():
640
- with gr.Column(scale=3):
641
- graficos_output = gr.Plot(label="Gr谩ficos de An谩lisis")
642
- with gr.Row():
643
- # Botones debajo del gr谩fico
644
- graficar_btn = gr.Button("馃搳 Graficar", variant="primary")
645
- with gr.Column(scale=1):
646
- puntos_seleccionados = gr.CheckboxGroup(
647
- choices=[],
648
- label="Seleccionar Puntos para Ajustar",
649
- )
650
- recalcular_btn = gr.Button("馃攣 Recalcular", variant="primary")
651
-
652
- # Opciones de personalizaci贸n de gr谩ficos
653
  with gr.Row():
654
  # Paletas de colores disponibles en Seaborn
655
  paletas_colores = ["deep", "muted", "pastel", "bright", "dark", "colorblind", "Set1", "Set2", "Set3"]
@@ -694,6 +640,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
694
  mostrar_linea_ajuste = gr.Checkbox(value=True, label="Mostrar L铆nea de Ajuste")
695
  mostrar_linea_ideal = gr.Checkbox(value=True, label="Mostrar L铆nea Ideal")
696
  mostrar_puntos = gr.Checkbox(value=True, label="Mostrar Puntos")
 
697
 
698
  with gr.Row():
699
  copiar_btn = gr.Button("馃搵 Copiar Informe", variant="secondary")
@@ -707,176 +654,148 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
707
  # Informe al final
708
  informe_output = gr.Markdown(elem_id="informe_output")
709
 
710
- # Eventos
 
 
711
 
712
- # Evento al presionar el bot贸n Calcular
713
- calcular_btn.click(
714
- fn=actualizar_analisis,
715
- inputs=[tabla_output, replicas_slider, unidad_input],
716
- outputs=[estado_output, graficos_output, informe_output, tabla_output, puntos_seleccionados]
717
- )
718
 
719
- # Evento para graficar con opciones seleccionadas
720
- graficar_btn.click(
721
- fn=lambda df, n_replicas, unidad_medida, pal_p, est_p, pal_aj, est_aj, pal_id, est_id, pal_be, m_aj, m_id, m_p: generar_graficos(
722
- calcular_promedio_desviacion(df, n_replicas, unidad_medida),
723
- n_replicas,
724
- unidad_medida,
725
- pal_p,
726
- est_p,
727
- pal_aj,
728
- est_aj,
729
- pal_id,
730
- est_id,
731
- pal_be,
732
- m_aj,
733
- m_id,
734
- m_p
735
- ),
736
- inputs=[
737
- tabla_output, replicas_slider, unidad_input,
738
- palette_puntos_dropdown, estilo_puntos_dropdown,
739
- palette_linea_ajuste_dropdown, estilo_linea_ajuste_dropdown,
740
- palette_linea_ideal_dropdown, estilo_linea_ideal_dropdown,
741
- palette_barras_error_dropdown,
742
- mostrar_linea_ajuste, mostrar_linea_ideal, mostrar_puntos
743
- ],
744
- outputs=graficos_output
745
- )
746
 
747
- # Evento para recalcular basado en puntos seleccionados
748
- recalcular_btn.click(
749
- fn=recalcular,
750
- inputs=[
751
- tabla_output, replicas_slider, unidad_input,
752
- puntos_seleccionados,
753
- palette_puntos_dropdown, estilo_puntos_dropdown,
754
- palette_linea_ajuste_dropdown, estilo_linea_ajuste_dropdown,
755
- palette_linea_ideal_dropdown, estilo_linea_ideal_dropdown,
756
- palette_barras_error_dropdown,
757
- mostrar_linea_ajuste, mostrar_linea_ideal, mostrar_puntos
758
- ],
759
- outputs=[estado_output, graficos_output, informe_output, tabla_output, puntos_seleccionados]
760
- )
761
 
762
- # Evento para limpiar datos
763
- limpiar_btn.click(
764
- fn=limpiar_datos,
765
- inputs=[replicas_slider],
766
- outputs=[concentracion_input, unidad_input, filas_slider, tabla_output, estado_output, graficos_output, informe_output, puntos_seleccionados]
767
- )
768
 
769
- # Eventos de los botones de ejemplo
770
- ejemplo_ufc_btn.click(
771
- fn=cargar_ejemplo_ufc,
772
- inputs=[replicas_slider],
773
- outputs=[concentracion_input, unidad_input, filas_slider, tabla_output, puntos_seleccionados]
774
- )
775
 
776
- ejemplo_od_btn.click(
777
- fn=cargar_ejemplo_od,
778
- inputs=[replicas_slider],
779
- outputs=[concentracion_input, unidad_input, filas_slider, tabla_output, puntos_seleccionados]
780
- )
 
781
 
782
- # Evento para generar datos sint茅ticos
783
- sinteticos_btn.click(
784
- fn=generar_datos_sinteticos_evento,
785
- inputs=[tabla_output, replicas_slider, unidad_input],
786
- outputs=tabla_output
787
- )
788
 
789
- # Evento al presionar el bot贸n Ajustar Decimales
790
- ajustar_decimales_btn.click(
791
- fn=ajustar_decimales_evento,
792
- inputs=[tabla_output, decimales_slider],
793
- outputs=tabla_output
794
- )
795
 
796
- # Actualizar tabla al cambiar los par谩metros (sin borrar "Concentraci贸n Real")
797
- def actualizar_tabla_wrapper(df, filas, conc, unidad, replicas):
798
- return actualizar_tabla_evento(df, filas, conc, unidad, replicas)
 
 
799
 
800
- concentracion_input.change(
801
- fn=actualizar_tabla_wrapper,
802
- inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
803
- outputs=tabla_output
804
- )
805
 
806
- unidad_input.change(
807
- fn=actualizar_tabla_wrapper,
808
- inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
809
- outputs=tabla_output
810
- )
811
 
812
- filas_slider.change(
813
- fn=actualizar_tabla_wrapper,
814
- inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
815
- outputs=tabla_output
816
- )
817
 
818
- replicas_slider.change(
819
- fn=actualizar_tabla_wrapper,
820
- inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
821
- outputs=tabla_output
822
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
823
 
824
- # No agregamos un evento para decimales_slider.change, para evitar borrar la columna "Concentraci贸n Real"
825
-
826
- # Evento de copiar informe utilizando JavaScript
827
- copiar_btn.click(
828
- None,
829
- [],
830
- [],
831
- js="""
832
- function() {
833
- const informeElement = document.querySelector('#informe_output');
834
- const range = document.createRange();
835
- range.selectNode(informeElement);
836
- window.getSelection().removeAllRanges();
837
- window.getSelection().addRange(range);
838
- document.execCommand('copy');
839
- window.getSelection().removeAllRanges();
840
- alert('Informe copiado al portapapeles');
841
- }
842
- """
843
- )
844
 
845
- # Eventos de exportar informes
846
- exportar_word_btn.click(
847
- fn=exportar_word,
848
- inputs=[tabla_output, informe_output, unidad_input],
849
- outputs=exportar_word_file
850
- )
851
 
852
- exportar_latex_btn.click(
853
- fn=lambda df, informe_md, unidad_medida: exportar_latex(df, informe_md, unidad_medida),
854
- inputs=[tabla_output, informe_output, unidad_input],
855
- outputs=exportar_latex_file
 
 
 
 
 
 
 
 
 
 
 
856
  )
857
 
858
- # Inicializar la interfaz con el ejemplo base
859
- def iniciar_con_ejemplo():
860
- n_replicas = 1
861
- df = generar_tabla(7, 2000000, "UFC", n_replicas)
862
- # Valores reales de ejemplo
863
- df[f"Concentraci贸n Real 1 (UFC)"] = [2000000, 1600000, 1200000, 800000, 400000, 200000, 100000]
864
- estado, fig, informe, df_actualizado, lista_puntos_update = actualizar_analisis(df, n_replicas, "UFC")
865
- return (
866
- 2000000,
867
- "UFC",
868
- 7,
869
- df_actualizado,
870
- estado,
871
- fig,
872
- informe,
873
- lista_puntos_update
874
- )
875
-
876
- interfaz.load(
877
- fn=iniciar_con_ejemplo,
878
- outputs=[concentracion_input, unidad_input, filas_slider, tabla_output, estado_output, graficos_output, informe_output, puntos_seleccionados]
879
- )
880
 
881
  # Lanzar la interfaz
882
  if __name__ == "__main__":
 
95
  sns.set(style="whitegrid")
96
  plt.rcParams.update({'figure.autolayout': True})
97
 
98
+ fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
99
 
100
  # Obtener colores de las paletas
101
  colors_puntos = sns.color_palette(palette_puntos, as_cmap=False)
 
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})"
279
 
280
  # Convertir columnas a num茅rico
281
+ df[col_predicha_num] = pd.to_numeric(df[col_predicha_num], errors='coerce')
282
+ df[col_real_promedio] = pd.to_numeric(df[col_real_promedio], errors='coerce')
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
 
289
  # Calcular la regresi贸n y agregar 'Ajuste Lineal'
290
  slope, intercept, r_value, p_value, std_err = stats.linregress(df_valid[col_predicha_num], df_valid[col_real_promedio])
291
  df_valid['Ajuste Lineal'] = intercept + slope * df_valid[col_predicha_num]
292
 
293
+ # Generar gr谩fico con opciones predeterminadas
294
  fig = generar_graficos(
295
  df_valid, n_replicas, unidad_medida,
296
+ palette_puntos='deep', estilo_puntos='o',
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
 
304
+ return estado, fig, informe, df
 
305
 
306
+ def actualizar_graficos(df, n_replicas, unidad_medida,
307
+ palette_puntos, estilo_puntos,
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"
 
325
  df_valid = df.dropna(subset=[col_predicha_num, col_real_promedio])
326
 
327
  if len(df_valid) < 2:
328
+ return None
 
 
 
 
329
 
330
+ # Generar gr谩fico con opciones seleccionadas
331
  fig = generar_graficos(
332
  df_valid, n_replicas, unidad_medida,
333
+ palette_puntos, estilo_puntos,
334
+ palette_linea_ajuste, estilo_linea_ajuste,
335
+ palette_linea_ideal, estilo_linea_ideal,
336
+ palette_barras_error,
337
+ mostrar_linea_ajuste, mostrar_linea_ideal, mostrar_puntos
338
  )
339
 
340
+ return fig
 
 
 
 
 
 
341
 
342
  def exportar_informe_word(df_valid, informe_md, unidad_medida):
343
  # Crear documento Word
 
367
  leyenda = doc.add_paragraph('Figura 1. Gr谩fico de calibraci贸n.')
368
  leyenda_format = leyenda.paragraph_format
369
  leyenda_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
370
+ leyenda.style = doc.styles['Caption']
 
 
 
371
 
372
  # Agregar contenido del informe
373
  doc.add_heading('Resumen Estad铆stico', level=1)
 
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]
455
 
456
  # Convertir columnas a num茅rico
457
  df_valid[col_predicha_num] = pd.to_numeric(df_valid[col_predicha_num], errors='coerce')
 
593
 
594
  with gr.Tab("馃搳 An谩lisis y Reporte"):
595
  estado_output = gr.Textbox(label="Estado", interactive=False)
596
+ graficos_output = gr.Plot(label="Gr谩ficos de An谩lisis")
597
+
598
+ # Opciones y botones debajo del gr谩fico
 
 
 
 
 
 
 
 
 
 
 
599
  with gr.Row():
600
  # Paletas de colores disponibles en Seaborn
601
  paletas_colores = ["deep", "muted", "pastel", "bright", "dark", "colorblind", "Set1", "Set2", "Set3"]
 
640
  mostrar_linea_ajuste = gr.Checkbox(value=True, label="Mostrar L铆nea de Ajuste")
641
  mostrar_linea_ideal = gr.Checkbox(value=True, label="Mostrar L铆nea Ideal")
642
  mostrar_puntos = gr.Checkbox(value=True, label="Mostrar Puntos")
643
+ graficar_btn = gr.Button("馃搳 Graficar", variant="primary")
644
 
645
  with gr.Row():
646
  copiar_btn = gr.Button("馃搵 Copiar Informe", variant="secondary")
 
654
  # Informe al final
655
  informe_output = gr.Markdown(elem_id="informe_output")
656
 
657
+ # Eventos
658
+ input_components = [tabla_output]
659
+ output_components = [estado_output, graficos_output, informe_output, tabla_output]
660
 
661
+ # Evento al presionar el bot贸n Calcular
662
+ calcular_btn.click(
663
+ fn=actualizar_analisis,
664
+ inputs=[tabla_output, replicas_slider, unidad_input],
665
+ outputs=output_components
666
+ )
667
 
668
+ # Evento para graficar con opciones seleccionadas
669
+ graficar_btn.click(
670
+ fn=actualizar_graficos,
671
+ inputs=[
672
+ tabla_output, replicas_slider, unidad_input,
673
+ palette_puntos_dropdown, estilo_puntos_dropdown,
674
+ palette_linea_ajuste_dropdown, estilo_linea_ajuste_dropdown,
675
+ palette_linea_ideal_dropdown, estilo_linea_ideal_dropdown,
676
+ palette_barras_error_dropdown,
677
+ mostrar_linea_ajuste, mostrar_linea_ideal, mostrar_puntos
678
+ ],
679
+ outputs=graficos_output
680
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
681
 
682
+ # Evento para limpiar datos
683
+ limpiar_btn.click(
684
+ fn=limpiar_datos,
685
+ inputs=[replicas_slider],
686
+ outputs=[concentracion_input, unidad_input, filas_slider, tabla_output, estado_output, graficos_output, informe_output]
687
+ )
 
 
 
 
 
 
 
 
688
 
689
+ # Eventos de los botones de ejemplo
690
+ ejemplo_ufc_btn.click(
691
+ fn=cargar_ejemplo_ufc,
692
+ inputs=[replicas_slider],
693
+ outputs=[concentracion_input, unidad_input, filas_slider, tabla_output]
694
+ )
695
 
696
+ ejemplo_od_btn.click(
697
+ fn=cargar_ejemplo_od,
698
+ inputs=[replicas_slider],
699
+ outputs=[concentracion_input, unidad_input, filas_slider, tabla_output]
700
+ )
 
701
 
702
+ # Evento para generar datos sint茅ticos
703
+ sinteticos_btn.click(
704
+ fn=generar_datos_sinteticos_evento,
705
+ inputs=[tabla_output, replicas_slider, unidad_input],
706
+ outputs=tabla_output
707
+ )
708
 
709
+ # Evento al presionar el bot贸n Ajustar Decimales
710
+ ajustar_decimales_btn.click(
711
+ fn=ajustar_decimales_evento,
712
+ inputs=[tabla_output, decimales_slider],
713
+ outputs=tabla_output
714
+ )
715
 
716
+ # Actualizar tabla al cambiar los par谩metros (sin borrar "Concentraci贸n Real")
717
+ def actualizar_tabla_wrapper(df, filas, conc, unidad, replicas):
718
+ return actualizar_tabla_evento(df, filas, conc, unidad, replicas)
 
 
 
719
 
720
+ concentracion_input.change(
721
+ fn=actualizar_tabla_wrapper,
722
+ inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
723
+ outputs=tabla_output
724
+ )
725
 
726
+ unidad_input.change(
727
+ fn=actualizar_tabla_wrapper,
728
+ inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
729
+ outputs=tabla_output
730
+ )
731
 
732
+ filas_slider.change(
733
+ fn=actualizar_tabla_wrapper,
734
+ inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
735
+ outputs=tabla_output
736
+ )
737
 
738
+ replicas_slider.change(
739
+ fn=actualizar_tabla_wrapper,
740
+ inputs=[tabla_output, filas_slider, concentracion_input, unidad_input, replicas_slider],
741
+ outputs=tabla_output
742
+ )
743
 
744
+ # No agregamos un evento para decimales_slider.change, para evitar borrar la columna "Concentraci贸n Real"
745
+
746
+ # Evento de copiar informe utilizando JavaScript
747
+ copiar_btn.click(
748
+ None,
749
+ [],
750
+ [],
751
+ js="""
752
+ function() {
753
+ const informeElement = document.querySelector('#informe_output');
754
+ const range = document.createRange();
755
+ range.selectNode(informeElement);
756
+ window.getSelection().removeAllRanges();
757
+ window.getSelection().addRange(range);
758
+ document.execCommand('copy');
759
+ window.getSelection().removeAllRanges();
760
+ alert('Informe copiado al portapapeles');
761
+ }
762
+ """
763
+ )
764
 
765
+ # Eventos de exportar informes
766
+ exportar_word_btn.click(
767
+ fn=exportar_word,
768
+ inputs=[tabla_output, informe_output, unidad_input],
769
+ outputs=exportar_word_file
770
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
771
 
772
+ exportar_latex_btn.click(
773
+ fn=exportar_latex,
774
+ inputs=[tabla_output, informe_output],
775
+ outputs=exportar_latex_file
776
+ )
 
777
 
778
+ # Inicializar la interfaz con el ejemplo base
779
+ def iniciar_con_ejemplo():
780
+ n_replicas = 1
781
+ df = generar_tabla(7, 2000000, "UFC", n_replicas)
782
+ # Valores reales de ejemplo
783
+ df[f"Concentraci贸n Real 1 (UFC)"] = [2000000, 1600000, 1200000, 800000, 400000, 200000, 100000]
784
+ estado, fig, informe, df = actualizar_analisis(df, n_replicas, "UFC")
785
+ return (
786
+ 2000000,
787
+ "UFC",
788
+ 7,
789
+ df,
790
+ estado,
791
+ fig,
792
+ informe
793
  )
794
 
795
+ interfaz.load(
796
+ fn=iniciar_con_ejemplo,
797
+ outputs=[concentracion_input, unidad_input, filas_slider, tabla_output, estado_output, graficos_output, informe_output]
798
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
799
 
800
  # Lanzar la interfaz
801
  if __name__ == "__main__":