C2MV commited on
Commit
6f3a203
verified
1 Parent(s): d71d9d8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +466 -120
app.py CHANGED
@@ -592,35 +592,30 @@ def actualizar_tabla_evento(df, n_filas, concentracion, unidad, n_replicas, deci
592
 
593
  def cargar_excel(file):
594
  # Leer el archivo Excel
595
- df = pd.read_excel(file.name)
596
 
597
- # Verificar que el archivo tenga las columnas requeridas
598
- if 'Concentraci贸n' not in df.columns:
599
- return "El archivo debe tener una columna llamada 'Concentraci贸n'.", None, None, None, None, None, None
600
 
601
- # Obtener las columnas de absorbancia
602
- columnas_absorbancia = [col for col in df.columns if 'Absorbancia' in col]
603
-
604
- if not columnas_absorbancia:
605
- return "El archivo debe tener al menos una columna de 'Absorbancia'.", None, None, None, None, None, None
606
-
607
- # Configurar par谩metros
608
- concentracion_inicial = df['Concentraci贸n'].max()
609
- unidad_medida = "Absorbancia"
610
- n_filas = len(df)
611
- n_replicas = len(columnas_absorbancia)
612
 
613
  # Generar la tabla base
614
- df_base = pd.DataFrame()
615
- df_base['Concentraci贸n Predicha Num茅rica'] = df['Concentraci贸n']
616
 
617
- # A帽adir las columnas de absorbancia
618
- for i, col in enumerate(columnas_absorbancia, start=1):
619
- df_base[f"Concentraci贸n Real {i} ({unidad_medida})"] = df[col]
 
620
 
621
  return concentracion_inicial, unidad_medida, n_filas, n_replicas, df_base, "", None, ""
622
 
623
- def calcular_regresion_tabla_principal(df, unidad_medida, columnas_seleccionadas,
624
  palette_puntos, estilo_puntos,
625
  palette_linea_ajuste, estilo_linea_ajuste,
626
  mostrar_linea_ajuste, mostrar_puntos,
@@ -632,106 +627,203 @@ def calcular_regresion_tabla_principal(df, unidad_medida, columnas_seleccionadas
632
  return "Datos insuficientes", None, None, None
633
 
634
  col_concentracion = "Concentraci贸n Predicha Num茅rica"
 
 
 
 
 
 
 
 
 
 
 
635
 
636
- # Verificar que haya columnas seleccionadas
637
- if not columnas_seleccionadas:
638
- return "Debe seleccionar al menos una columna de absorbancia.", None, None, None
639
 
640
- graficos = []
641
- dfs_resumen = []
642
 
643
- for col_absorbancia in columnas_seleccionadas:
644
- df_valid = df[[col_concentracion, col_absorbancia]].dropna()
645
 
646
- # Convertir columnas a num茅rico
647
- df_valid[col_concentracion] = pd.to_numeric(df_valid[col_concentracion], errors='coerce')
648
- df_valid[col_absorbancia] = pd.to_numeric(df_valid[col_absorbancia], errors='coerce')
649
 
650
- if len(df_valid) < 2:
651
- continue
652
 
653
- # Calcular regresi贸n lineal
654
- slope, intercept, r_value, p_value, std_err = stats.linregress(df_valid[col_concentracion], df_valid[col_absorbancia])
655
 
656
- # Generar gr谩fico
657
- sns.set(style="whitegrid")
658
- fig, ax = plt.subplots(figsize=(8, 6))
659
 
660
- # Obtener colores de las paletas
661
- colors_puntos = sns.color_palette(palette_puntos, as_cmap=False)
662
- colors_linea_ajuste = sns.color_palette(palette_linea_ajuste, as_cmap=False)
663
 
664
- color_puntos = colors_puntos[0]
665
- color_linea_ajuste = colors_linea_ajuste[0]
 
 
 
 
 
 
 
 
 
 
 
 
 
666
 
667
- if mostrar_puntos:
668
- ax.scatter(
669
- df_valid[col_concentracion],
670
- df_valid[col_absorbancia],
671
- color=color_puntos,
672
- s=100,
673
- marker=estilo_puntos,
674
- label='Datos'
675
- )
676
 
677
- if mostrar_linea_ajuste:
678
- ax.plot(
679
- df_valid[col_concentracion],
680
- intercept + slope * df_valid[col_concentracion],
681
- color=color_linea_ajuste,
682
- linestyle=estilo_linea_ajuste,
683
- label='Ajuste Lineal'
684
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
685
 
686
- # T铆tulo y etiquetas personalizadas
687
- ax.set_xlabel(eje_x_personalizado if eje_x_personalizado else 'Concentraci贸n')
688
- ax.set_ylabel(eje_y_personalizado if eje_y_personalizado else f'{col_absorbancia}')
689
- ax.set_title(titulo_grafico_personalizado if titulo_grafico_personalizado else f'Regresi贸n Lineal: {col_absorbancia}')
690
-
691
- # Posicionar la leyenda seg煤n la opci贸n seleccionada
692
- ax.legend(loc=legend_location)
693
-
694
- # A帽adir ecuaci贸n y R虏 en el gr谩fico
695
- ax.annotate(
696
- f'y = {intercept:.4f} + {slope:.4f}x\n$R^2$ = {r_value**2:.4f}',
697
- xy=(0.05, 0.95),
698
- xycoords='axes fraction',
699
- fontsize=12,
700
- backgroundcolor='white',
701
- verticalalignment='top'
 
 
 
 
702
  )
703
 
704
- graficos.append(fig)
 
 
 
705
 
706
- # Crear tabla resumida
707
- df_resumen = df_valid[[col_concentracion, col_absorbancia]].copy()
708
- df_resumen.columns = ['Concentraci贸n', f'{col_absorbancia}']
709
- dfs_resumen.append(df_resumen)
 
 
 
 
 
 
 
 
710
 
711
- if not graficos:
712
- return "No se pudo calcular la regresi贸n para las columnas seleccionadas.", None, None, None
 
713
 
714
- return "Regresi贸n calculada exitosamente", graficos, None, dfs_resumen
715
 
716
- def actualizar_opciones_columnas(df):
 
717
  if df is None or df.empty:
718
  update = gr.update(choices=[], value=[])
719
  else:
720
- columnas_absorbancia = [col for col in df.columns if 'Absorbancia' in col or 'Concentraci贸n Real' in col]
721
- update = gr.update(choices=columnas_absorbancia, value=columnas_absorbancia)
722
- return update
723
 
724
  # Interfaz Gradio
725
  with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
726
  gr.Markdown("""
727
  # 馃搳 Sistema Avanzado de Calibraci贸n con An谩lisis Estad铆stico
728
- Cargue un archivo Excel con m煤ltiples columnas de absorbancia y seleccione cu谩les desea incluir en el an谩lisis.
729
  """)
730
 
731
  with gr.Tab("馃摑 Datos de Calibraci贸n"):
732
  with gr.Row():
733
- cargar_excel_btn = gr.UploadButton("馃搨 Cargar Excel", file_types=[".xlsx"], variant="primary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
734
  limpiar_btn = gr.Button("馃棏 Limpiar Datos", variant="secondary")
 
 
 
 
 
 
 
735
 
736
  tabla_output = gr.DataFrame(
737
  wrap=True,
@@ -740,12 +832,82 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
740
  type="pandas",
741
  )
742
 
743
- with gr.Tab("馃搱 An谩lisis de Regresi贸n"):
744
- gr.Markdown("## Ajuste de Regresi贸n utilizando datos seleccionados")
 
745
 
746
- # Casillas para seleccionar columnas
747
- columnas_seleccionadas = gr.CheckboxGroup(
748
- label="Seleccione las columnas de absorbancia a incluir en el an谩lisis de regresi贸n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
749
  choices=[],
750
  value=[],
751
  )
@@ -789,61 +951,245 @@ with gr.Blocks(theme=gr.themes.Soft()) as interfaz:
789
 
790
  # Campos de texto para personalizar t铆tulo y ejes
791
  with gr.Row():
 
 
 
 
792
  titulo_grafico_personalizado = gr.Textbox(
793
- label="T铆tulo del Gr谩fico",
794
- placeholder="Regresi贸n Lineal"
 
 
 
 
 
 
 
 
 
 
795
  )
796
 
797
  with gr.Row():
798
  eje_x_personalizado = gr.Textbox(
799
- label="Etiqueta del Eje X",
800
- placeholder="Concentraci贸n"
801
  )
802
  eje_y_personalizado = gr.Textbox(
803
- label="Etiqueta del Eje Y",
804
- placeholder="Absorbancia"
805
  )
806
 
807
  calcular_regresion_btn = gr.Button("Calcular Regresi贸n")
808
 
809
  # Salidas
810
  estado_regresion_output = gr.Textbox(label="Estado de la Regresi贸n", interactive=False)
811
- graficos_output = gr.Gallery(label="Gr谩ficos Generados").style(grid=2, height='auto')
812
- tabla_resumen_output = gr.DataFrame(label="Tablas Resumidas")
 
813
 
814
- # Eventos
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
815
  cargar_excel_btn.upload(
816
  fn=cargar_excel,
817
  inputs=[cargar_excel_btn],
818
- outputs=[None, None, None, None, tabla_output, None, None, None]
819
  )
820
 
821
- tabla_output.change(
822
- fn=actualizar_opciones_columnas,
823
- inputs=[tabla_output],
824
- outputs=[columnas_seleccionadas]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
825
  )
826
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
827
  calcular_regresion_btn.click(
828
  fn=calcular_regresion_tabla_principal,
829
  inputs=[
830
- tabla_output, None, columnas_seleccionadas,
831
  palette_puntos_regresion, estilo_puntos_regresion,
832
  palette_linea_ajuste_regresion, estilo_linea_ajuste_regresion,
833
  mostrar_linea_ajuste_regresion, mostrar_puntos_regresion,
834
- legend_location_dropdown, None,
835
- None, titulo_grafico_personalizado,
836
- None, None,
837
  eje_x_personalizado, eje_y_personalizado
838
  ],
839
- outputs=[estado_regresion_output, graficos_output, None, tabla_resumen_output]
840
- )
841
-
842
- limpiar_btn.click(
843
- fn=lambda: (None, gr.update(value=None)),
844
- inputs=[],
845
- outputs=[tabla_output, columnas_seleccionadas]
846
  )
847
 
 
848
  if __name__ == "__main__":
849
  interfaz.launch()
 
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
 
601
+ # Obtener la primera pesta帽a como referencia
602
+ primera_pesta帽a = next(iter(df.values()))
603
+ concentracion_inicial = primera_pesta帽a.iloc[0, 0]
604
+ unidad_medida = primera_pesta帽a.columns[0].split('(')[-1].split(')')[0]
605
+ n_filas = len(primera_pesta帽a)
606
+ n_replicas = len(df)
 
 
 
 
 
607
 
608
  # Generar la tabla base
609
+ df_base = generar_tabla(n_filas, concentracion_inicial, unidad_medida, n_replicas)
 
610
 
611
+ # Llenar la tabla con los datos de cada pesta帽a
612
+ for i, (sheet_name, sheet_df) in enumerate(df.items(), start=1):
613
+ col_real = f"Concentraci贸n Real {i} ({unidad_medida})"
614
+ df_base[col_real] = sheet_df.iloc[:, 1].values
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,
 
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("""
779
  # 馃搳 Sistema Avanzado de Calibraci贸n con An谩lisis Estad铆stico
780
+ Configure los par谩metros, edite los valores en la tabla y luego presione "Calcular" para obtener el an谩lisis.
781
  """)
782
 
783
  with gr.Tab("馃摑 Datos de Calibraci贸n"):
784
  with gr.Row():
785
+ concentracion_input = gr.Number(
786
+ value=2000000,
787
+ label="Concentraci贸n Inicial",
788
+ precision=0
789
+ )
790
+ unidad_input = gr.Textbox(
791
+ value="UFC",
792
+ label="Unidad de Medida",
793
+ placeholder="UFC, OD, etc..."
794
+ )
795
+ filas_slider = gr.Slider(
796
+ minimum=1,
797
+ maximum=20,
798
+ value=7,
799
+ step=1,
800
+ label="N煤mero de filas"
801
+ )
802
+ decimales_slider = gr.Slider(
803
+ minimum=0,
804
+ maximum=5,
805
+ value=3,
806
+ step=1,
807
+ label="N煤mero de Decimales"
808
+ )
809
+ replicas_slider = gr.Slider(
810
+ minimum=1,
811
+ maximum=10,
812
+ value=1,
813
+ step=1,
814
+ label="N煤mero de R茅plicas"
815
+ )
816
+
817
+ with gr.Row():
818
+ calcular_btn = gr.Button("馃攧 Calcular", variant="primary")
819
  limpiar_btn = gr.Button("馃棏 Limpiar Datos", variant="secondary")
820
+ ajustar_decimales_btn = gr.Button("馃洜 Ajustar Decimales", variant="secondary")
821
+
822
+ with gr.Row():
823
+ ejemplo_ufc_btn = gr.Button("馃搵 Cargar Ejemplo UFC", variant="secondary")
824
+ ejemplo_od_btn = gr.Button("馃搵 Cargar Ejemplo OD", variant="secondary")
825
+ sinteticos_btn = gr.Button("馃И Generar Datos Sint茅ticos", variant="secondary")
826
+ cargar_excel_btn = gr.UploadButton("馃搨 Cargar Excel", file_types=[".xlsx"], variant="secondary")
827
 
828
  tabla_output = gr.DataFrame(
829
  wrap=True,
 
832
  type="pandas",
833
  )
834
 
835
+ with gr.Tab("馃搳 An谩lisis y Reporte"):
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
849
+ paletas_colores = ["deep", "muted", "pastel", "bright", "dark", "colorblind", "Set1", "Set2", "Set3"]
850
+
851
+ palette_puntos_dropdown = gr.Dropdown(
852
+ choices=paletas_colores,
853
+ value="deep",
854
+ label="Paleta para Puntos"
855
+ )
856
+ estilo_puntos_dropdown = gr.Dropdown(
857
+ choices=["o", "s", "^", "D", "v", "<", ">", "h", "H", "p", "*", "X", "d"],
858
+ value="o",
859
+ label="Estilo de Puntos"
860
+ )
861
+ palette_linea_ajuste_dropdown = gr.Dropdown(
862
+ choices=paletas_colores,
863
+ value="muted",
864
+ label="Paleta L铆nea de Ajuste"
865
+ )
866
+ estilo_linea_ajuste_dropdown = gr.Dropdown(
867
+ choices=["-", "--", "-.", ":"],
868
+ value="-",
869
+ label="Estilo L铆nea de Ajuste"
870
+ )
871
+
872
+ with gr.Row():
873
+ palette_linea_ideal_dropdown = gr.Dropdown(
874
+ choices=paletas_colores,
875
+ value="bright",
876
+ label="Paleta L铆nea Ideal"
877
+ )
878
+ estilo_linea_ideal_dropdown = gr.Dropdown(
879
+ choices=["--", "-", "-.", ":"],
880
+ value="--",
881
+ label="Estilo L铆nea Ideal"
882
+ )
883
+ palette_barras_error_dropdown = gr.Dropdown(
884
+ choices=paletas_colores,
885
+ value="pastel",
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
+
893
+ with gr.Row():
894
+ copiar_btn = gr.Button("馃搵 Copiar Informe", variant="secondary")
895
+ exportar_word_btn = gr.Button("馃捑 Exportar Informe Word", variant="primary")
896
+ exportar_latex_btn = gr.Button("馃捑 Exportar Informe LaTeX", variant="primary")
897
+
898
+ with gr.Row():
899
+ exportar_word_file = gr.File(label="Informe en Word")
900
+ exportar_latex_file = gr.File(label="Informe en LaTeX")
901
+
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
  )
 
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
1006
+ graficar_btn.click(
1007
+ fn=actualizar_graficos,
1008
+ inputs=[
1009
+ tabla_output, replicas_slider, unidad_input,
1010
+ palette_puntos_dropdown, estilo_puntos_dropdown,
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,
1046
+ inputs=[replicas_slider],
1047
+ outputs=[concentracion_input, unidad_input, filas_slider, tabla_output, estado_output, graficos_output, informe_output]
1048
+ )
1049
+
1050
+ # Eventos de los botones de ejemplo
1051
+ ejemplo_ufc_btn.click(
1052
+ fn=cargar_ejemplo_ufc,
1053
+ inputs=[replicas_slider],
1054
+ outputs=[concentracion_input, unidad_input, filas_slider, tabla_output]
1055
+ )
1056
+
1057
+ ejemplo_od_btn.click(
1058
+ fn=cargar_ejemplo_od,
1059
+ inputs=[replicas_slider],
1060
+ outputs=[concentracion_input, unidad_input, filas_slider, tabla_output]
1061
+ )
1062
+
1063
+ # Evento para generar datos sint茅ticos
1064
+ sinteticos_btn.click(
1065
+ fn=generar_datos_sinteticos_evento,
1066
+ inputs=[tabla_output, replicas_slider, unidad_input],
1067
+ outputs=tabla_output
1068
+ )
1069
+
1070
+ # Evento para cargar archivo Excel
1071
  cargar_excel_btn.upload(
1072
  fn=cargar_excel,
1073
  inputs=[cargar_excel_btn],
1074
+ outputs=[concentracion_input, unidad_input, filas_slider, replicas_slider, tabla_output, estado_output, graficos_output, informe_output]
1075
  )
1076
 
1077
+ # Evento al presionar el bot贸n Ajustar Decimales
1078
+ ajustar_decimales_btn.click(
1079
+ fn=ajustar_decimales_evento,
1080
+ inputs=[tabla_output, decimales_slider],
1081
+ outputs=tabla_output
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(
1120
+ None,
1121
+ [],
1122
+ [],
1123
+ js="""
1124
+ function() {
1125
+ const informeElement = document.querySelector('#informe_output');
1126
+ const range = document.createRange();
1127
+ range.selectNode(informeElement);
1128
+ window.getSelection().removeAllRanges();
1129
+ window.getSelection().addRange(range);
1130
+ document.execCommand('copy');
1131
+ window.getSelection().removeAllRanges();
1132
+ alert('Informe copiado al portapapeles');
1133
+ }
1134
+ """
1135
+ )
1136
+
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
+
1150
+ # Inicializar la interfaz con el ejemplo base
1151
+ def iniciar_con_ejemplo():
1152
+ n_replicas = 1
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",
1163
+ 7,
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
1194
  if __name__ == "__main__":
1195
  interfaz.launch()