Update app.py
Browse files
app.py
CHANGED
@@ -41,20 +41,24 @@ class RSM_BoxBehnken:
|
|
41 |
"""
|
42 |
design = []
|
43 |
|
44 |
-
# Generar todas las combinaciones de
|
45 |
-
|
46 |
-
|
47 |
-
for
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
|
|
|
|
|
|
52 |
|
53 |
# Añadir corridas centrales
|
54 |
for _ in range(center_runs):
|
55 |
-
|
|
|
56 |
|
57 |
-
design_df = pd.DataFrame(design
|
58 |
self.design = design_df
|
59 |
|
60 |
# Mapear niveles codificados a naturales
|
@@ -178,7 +182,9 @@ class RSM_BoxBehnken:
|
|
178 |
|
179 |
# Obtener las combinaciones de factores para gráficos
|
180 |
for fixed_index, fixed_variable in enumerate(self.factor_names):
|
181 |
-
|
|
|
|
|
182 |
fig = self.plot_rsm_individual(fixed_variable, level)
|
183 |
if fig is not None:
|
184 |
self.all_figures.append(fig)
|
@@ -231,7 +237,10 @@ class RSM_BoxBehnken:
|
|
231 |
|
232 |
# Añadir puntos de los experimentos
|
233 |
experiments = self.data.copy()
|
234 |
-
|
|
|
|
|
|
|
235 |
fig.add_trace(go.Scatter3d(
|
236 |
x=experiments[var1],
|
237 |
y=experiments[var2],
|
@@ -267,6 +276,7 @@ class RSM_BoxBehnken:
|
|
267 |
'Glucosa': 'g/L',
|
268 |
'Extracto_de_Levadura': 'g/L',
|
269 |
'Triptofano': 'g/L',
|
|
|
270 |
'AIA_ppm': 'ppm',
|
271 |
# Agrega más unidades según tus variables
|
272 |
}
|
@@ -306,6 +316,28 @@ class RSM_BoxBehnken:
|
|
306 |
|
307 |
return fig
|
308 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
309 |
def generate_prediction_table(self):
|
310 |
"""
|
311 |
Genera una tabla con los valores actuales, predichos y residuales.
|
@@ -420,10 +452,12 @@ class RSM_BoxBehnken:
|
|
420 |
})
|
421 |
|
422 |
# Calcular la suma de cuadrados y grados de libertad para la curvatura
|
423 |
-
ss_curvature =
|
424 |
-
|
425 |
-
|
426 |
-
|
|
|
|
|
427 |
|
428 |
# Añadir la fila de curvatura a la tabla ANOVA
|
429 |
detailed_anova_table.loc[len(detailed_anova_table)] = ['Curvatura', ss_curvature, df_curvature, ss_curvature / df_curvature, np.nan, np.nan]
|
@@ -566,14 +600,13 @@ class RSM_BoxBehnken:
|
|
566 |
|
567 |
# --- Funciones para la Interfaz de Gradio ---
|
568 |
|
569 |
-
def
|
570 |
"""
|
571 |
-
|
572 |
-
Si example=True, carga un ejemplo predefinido.
|
573 |
"""
|
574 |
try:
|
575 |
-
if
|
576 |
-
#
|
577 |
if n_factors == 3:
|
578 |
factor_names = ['Glucosa', 'Extracto_de_Levadura', 'Triptofano']
|
579 |
factor_levels = [
|
@@ -581,6 +614,7 @@ def load_data(n_factors, factor_details, y_name, example=False):
|
|
581 |
{'min': 0.03, 'max': 0.3, 'levels': [0.03, 0.2, 0.3]},
|
582 |
{'min': 0.4, 'max': 0.9, 'levels': [0.4, 0.65, 0.9]}
|
583 |
]
|
|
|
584 |
# Crear instancia
|
585 |
rsm = RSM_BoxBehnken(factor_names, factor_levels, y_name)
|
586 |
design = rsm.generate_box_behnken_design()
|
@@ -588,7 +622,6 @@ def load_data(n_factors, factor_details, y_name, example=False):
|
|
588 |
response_values = [166.594, 177.557, 127.261, 147.573, 188.883, 224.527, 190.238, 226.483, 195.550, 149.493, 187.683, 148.621, 278.951, 297.238, 280.896]
|
589 |
rsm.set_response(response_values)
|
590 |
return rsm, design
|
591 |
-
# Ejemplo para 4 factores
|
592 |
elif n_factors == 4:
|
593 |
factor_names = ['Glucosa', 'Extracto_de_Levadura', 'Triptofano', 'Tiempo']
|
594 |
factor_levels = [
|
@@ -597,6 +630,7 @@ def load_data(n_factors, factor_details, y_name, example=False):
|
|
597 |
{'min': 0.4, 'max': 0.9, 'levels': [0.4, 0.65, 0.9]},
|
598 |
{'min': 24, 'max': 72, 'levels': [24, 48, 72]}
|
599 |
]
|
|
|
600 |
# Crear instancia
|
601 |
rsm = RSM_BoxBehnken(factor_names, factor_levels, y_name)
|
602 |
design = rsm.generate_box_behnken_design()
|
@@ -608,14 +642,20 @@ def load_data(n_factors, factor_details, y_name, example=False):
|
|
608 |
raise ValueError("Ejemplos solo disponibles para 3 y 4 factores.")
|
609 |
else:
|
610 |
# Cargar según la entrada del usuario
|
611 |
-
factor_names = [
|
612 |
-
factor_levels = [
|
|
|
|
|
|
|
|
|
|
|
|
|
613 |
# Crear instancia
|
614 |
rsm = RSM_BoxBehnken(factor_names, factor_levels, y_name)
|
615 |
design = rsm.generate_box_behnken_design()
|
616 |
return rsm, design
|
617 |
except Exception as e:
|
618 |
-
print(f"Error al cargar
|
619 |
return None, None
|
620 |
|
621 |
def fit_and_optimize(rsm, response_values):
|
@@ -636,7 +676,7 @@ def fit_and_optimize(rsm, response_values):
|
|
636 |
rsm.generate_all_plots()
|
637 |
|
638 |
# Formatear la ecuación para que se vea mejor en Markdown
|
639 |
-
equation_formatted = equation.replace(" + ", "<br>+ ").replace("
|
640 |
equation_formatted = f"### Ecuación del Modelo Simplificado:<br>{equation_formatted}"
|
641 |
|
642 |
# Guardar las tablas en Excel temporal
|
@@ -709,7 +749,7 @@ def create_gradio_interface():
|
|
709 |
factor_inputs = []
|
710 |
for i in range(6):
|
711 |
with gr.Row():
|
712 |
-
factor_name = gr.Textbox(label=f"Factor {i+1} Nombre", placeholder=f"Nombre del Factor {i+1}")
|
713 |
factor_min = gr.Number(label=f"Factor {i+1} Min", value=0.0)
|
714 |
factor_max = gr.Number(label=f"Factor {i+1} Max", value=1.0)
|
715 |
factor_inputs.append({'name': factor_name, 'min': factor_min, 'max': factor_max})
|
@@ -724,7 +764,7 @@ def create_gradio_interface():
|
|
724 |
gr.Markdown("### Diseño Box-Behnken")
|
725 |
design_output = gr.Dataframe(
|
726 |
headers=None,
|
727 |
-
label="Diseño Generado (Completa
|
728 |
interactive=True
|
729 |
)
|
730 |
submit_response_button = gr.Button("✅ Enviar Respuestas")
|
@@ -769,81 +809,45 @@ def create_gradio_interface():
|
|
769 |
with gr.Row():
|
770 |
download_plot_button = gr.DownloadButton("💾 Descargar Gráfico Actual (PNG)")
|
771 |
download_all_plots_button = gr.DownloadButton("💾 Descargar Todos los Gráficos (ZIP)")
|
772 |
-
|
773 |
-
with gr.Row():
|
774 |
-
copiar_btn = gr.Button("📋 Copiar Informe", variant="secondary")
|
775 |
-
exportar_word_btn = gr.Button("💾 Exportar Informe Word", variant="primary")
|
776 |
-
exportar_excel_btn = gr.Button("💾 Exportar Informe Excel", variant="primary")
|
777 |
-
|
778 |
# --- Funciones de la Interfaz ---
|
779 |
|
780 |
-
def
|
781 |
"""
|
782 |
-
|
783 |
"""
|
784 |
-
|
785 |
-
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
rsm = RSM_BoxBehnken(factor_names, factor_levels, y_name)
|
796 |
-
design = rsm.generate_box_behnken_design()
|
797 |
-
# Ejemplo de valores de respuesta
|
798 |
-
response_values = [166.594, 177.557, 127.261, 147.573, 188.883, 224.527, 190.238, 226.483, 195.550, 149.493, 187.683, 148.621, 278.951, 297.238, 280.896]
|
799 |
-
rsm.set_response(response_values)
|
800 |
-
return rsm, design
|
801 |
-
elif n_factors == 4:
|
802 |
-
factor_names = ['Glucosa', 'Extracto_de_Levadura', 'Triptofano', 'Tiempo']
|
803 |
-
factor_levels = [
|
804 |
-
{'min': 1.0, 'max': 5.5, 'levels': [1.0, 3.5, 5.5]},
|
805 |
-
{'min': 0.03, 'max': 0.3, 'levels': [0.03, 0.2, 0.3]},
|
806 |
-
{'min': 0.4, 'max': 0.9, 'levels': [0.4, 0.65, 0.9]},
|
807 |
-
{'min': 24, 'max': 72, 'levels': [24, 48, 72]}
|
808 |
-
]
|
809 |
-
y_name = 'AIA_ppm'
|
810 |
-
# Crear instancia
|
811 |
-
rsm = RSM_BoxBehnken(factor_names, factor_levels, y_name)
|
812 |
-
design = rsm.generate_box_behnken_design()
|
813 |
-
# Ejemplo de valores de respuesta (30 corridas para 4 factores)
|
814 |
-
response_values = [200 + np.random.normal(0, 10) for _ in range(len(design))]
|
815 |
-
rsm.set_response(response_values)
|
816 |
-
return rsm, design
|
817 |
-
else:
|
818 |
-
raise ValueError("Ejemplos solo disponibles para 3 y 4 factores.")
|
819 |
-
else:
|
820 |
-
# Cargar según la entrada del usuario
|
821 |
-
factor_names = [detail['name'] for detail in factor_details]
|
822 |
-
factor_levels = [{'min': detail['min'], 'max': detail['max'], 'levels': [detail['min'], (detail['min'] + detail['max']) / 2, detail['max']]} for detail in factor_details]
|
823 |
-
# Crear instancia
|
824 |
-
rsm = RSM_BoxBehnken(factor_names, factor_levels, y_name)
|
825 |
-
design = rsm.generate_box_behnken_design()
|
826 |
-
return rsm, design
|
827 |
-
|
828 |
-
def prepare_download_files(excel_path, zip_path):
|
829 |
"""
|
830 |
-
|
831 |
"""
|
832 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
833 |
|
834 |
# Cargar Diseño
|
835 |
load_button.click(
|
836 |
-
fn=
|
837 |
-
inputs=[
|
838 |
-
[gr.Row().components for gr.Row in gr.Blocks().__class__],
|
839 |
-
y_name_input,
|
840 |
-
load_example_checkbox],
|
841 |
outputs=[gr.State(), design_output]
|
842 |
)
|
843 |
-
|
844 |
-
# Enviar Respuestas
|
845 |
submit_response_button.click(
|
846 |
-
fn=
|
847 |
inputs=[gr.State(), design_output],
|
848 |
outputs=[
|
849 |
model_completo_output,
|
@@ -857,31 +861,73 @@ def create_gradio_interface():
|
|
857 |
anova_table_output,
|
858 |
download_all_plots_button,
|
859 |
download_excel_button,
|
860 |
-
|
861 |
]
|
862 |
)
|
863 |
|
864 |
-
#
|
865 |
-
|
866 |
-
|
867 |
-
|
868 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
869 |
)
|
870 |
|
871 |
# Descargar Todos los Gráficos en ZIP
|
872 |
download_all_plots_button.click(
|
873 |
-
fn=lambda
|
874 |
-
inputs=[
|
875 |
-
outputs=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
876 |
)
|
877 |
|
878 |
# Descargar Tablas en Word
|
879 |
download_word_button.click(
|
880 |
-
fn=lambda rsm_instance, tables_dict: export_word(rsm_instance, tables_dict),
|
881 |
inputs=[gr.State(), gr.State()],
|
882 |
outputs=[download_word_button]
|
883 |
)
|
884 |
-
|
885 |
return demo
|
886 |
|
887 |
# --- Función Principal ---
|
|
|
41 |
"""
|
42 |
design = []
|
43 |
|
44 |
+
# Generar todas las combinaciones de tres niveles para cada par de factores
|
45 |
+
for combination in itertools.combinations(self.factor_names, 2):
|
46 |
+
var1, var2 = combination
|
47 |
+
for level1 in [-1, 0, 1]:
|
48 |
+
for level2 in [-1, 0, 1]:
|
49 |
+
# Solo agregar puntos que formen el diseño Box-Behnken
|
50 |
+
if abs(level1) == 1 and abs(level2) == 1:
|
51 |
+
run = {var: 0 for var in self.factor_names}
|
52 |
+
run[var1] = level1
|
53 |
+
run[var2] = level2
|
54 |
+
design.append(run)
|
55 |
|
56 |
# Añadir corridas centrales
|
57 |
for _ in range(center_runs):
|
58 |
+
run = {var: 0 for var in self.factor_names}
|
59 |
+
design.append(run)
|
60 |
|
61 |
+
design_df = pd.DataFrame(design)
|
62 |
self.design = design_df
|
63 |
|
64 |
# Mapear niveles codificados a naturales
|
|
|
182 |
|
183 |
# Obtener las combinaciones de factores para gráficos
|
184 |
for fixed_index, fixed_variable in enumerate(self.factor_names):
|
185 |
+
# Usar los niveles originales para fijar la variable
|
186 |
+
fixed_levels = self.factor_levels[fixed_index]['levels']
|
187 |
+
for level in fixed_levels:
|
188 |
fig = self.plot_rsm_individual(fixed_variable, level)
|
189 |
if fig is not None:
|
190 |
self.all_figures.append(fig)
|
|
|
237 |
|
238 |
# Añadir puntos de los experimentos
|
239 |
experiments = self.data.copy()
|
240 |
+
# Convertir el nivel fijo a codificado para filtrar
|
241 |
+
fixed_level_coded = self.natural_to_coded(fixed_level, self.factor_names.index(fixed_variable))
|
242 |
+
# Filtrar experimentos donde la variable fija está cerca del nivel seleccionado (tolerancia pequeña)
|
243 |
+
experiments = experiments[np.isclose(experiments[fixed_variable], fixed_level, atol=1e-3)]
|
244 |
fig.add_trace(go.Scatter3d(
|
245 |
x=experiments[var1],
|
246 |
y=experiments[var2],
|
|
|
276 |
'Glucosa': 'g/L',
|
277 |
'Extracto_de_Levadura': 'g/L',
|
278 |
'Triptofano': 'g/L',
|
279 |
+
'Tiempo': 'Horas',
|
280 |
'AIA_ppm': 'ppm',
|
281 |
# Agrega más unidades según tus variables
|
282 |
}
|
|
|
316 |
|
317 |
return fig
|
318 |
|
319 |
+
def get_simplified_equation(self):
|
320 |
+
"""
|
321 |
+
Retorna la ecuación del modelo simplificado como una cadena de texto.
|
322 |
+
"""
|
323 |
+
if self.model_simplified is None:
|
324 |
+
print("Error: Ajusta el modelo simplificado primero.")
|
325 |
+
return None
|
326 |
+
|
327 |
+
coefficients = self.model_simplified.params
|
328 |
+
equation = f"{self.y_name} = {coefficients['Intercept']:.3f}"
|
329 |
+
|
330 |
+
for term, coef in coefficients.items():
|
331 |
+
if term != 'Intercept':
|
332 |
+
if term in self.factor_names:
|
333 |
+
equation += f" + {coef:.3f}*{term}"
|
334 |
+
elif term.startswith("I("):
|
335 |
+
equation += f" + {coef:.3f}*{term[2:-1]}"
|
336 |
+
else:
|
337 |
+
equation += f" + {coef:.3f}*{term.replace(':', '×')}"
|
338 |
+
|
339 |
+
return equation
|
340 |
+
|
341 |
def generate_prediction_table(self):
|
342 |
"""
|
343 |
Genera una tabla con los valores actuales, predichos y residuales.
|
|
|
452 |
})
|
453 |
|
454 |
# Calcular la suma de cuadrados y grados de libertad para la curvatura
|
455 |
+
ss_curvature = 0
|
456 |
+
for var in self.factor_names:
|
457 |
+
curvature_term = f"I({var}**2)"
|
458 |
+
if curvature_term in anova_reduced.index:
|
459 |
+
ss_curvature += anova_reduced.loc[curvature_term, 'sum_sq']
|
460 |
+
df_curvature = self.n_factors
|
461 |
|
462 |
# Añadir la fila de curvatura a la tabla ANOVA
|
463 |
detailed_anova_table.loc[len(detailed_anova_table)] = ['Curvatura', ss_curvature, df_curvature, ss_curvature / df_curvature, np.nan, np.nan]
|
|
|
600 |
|
601 |
# --- Funciones para la Interfaz de Gradio ---
|
602 |
|
603 |
+
def handle_load_design(n_factors, factor_inputs, y_name, load_example):
|
604 |
"""
|
605 |
+
Genera el diseño Box-Behnken según la configuración o carga un ejemplo.
|
|
|
606 |
"""
|
607 |
try:
|
608 |
+
if load_example:
|
609 |
+
# Cargar ejemplos predefinidos
|
610 |
if n_factors == 3:
|
611 |
factor_names = ['Glucosa', 'Extracto_de_Levadura', 'Triptofano']
|
612 |
factor_levels = [
|
|
|
614 |
{'min': 0.03, 'max': 0.3, 'levels': [0.03, 0.2, 0.3]},
|
615 |
{'min': 0.4, 'max': 0.9, 'levels': [0.4, 0.65, 0.9]}
|
616 |
]
|
617 |
+
y_name = 'AIA_ppm'
|
618 |
# Crear instancia
|
619 |
rsm = RSM_BoxBehnken(factor_names, factor_levels, y_name)
|
620 |
design = rsm.generate_box_behnken_design()
|
|
|
622 |
response_values = [166.594, 177.557, 127.261, 147.573, 188.883, 224.527, 190.238, 226.483, 195.550, 149.493, 187.683, 148.621, 278.951, 297.238, 280.896]
|
623 |
rsm.set_response(response_values)
|
624 |
return rsm, design
|
|
|
625 |
elif n_factors == 4:
|
626 |
factor_names = ['Glucosa', 'Extracto_de_Levadura', 'Triptofano', 'Tiempo']
|
627 |
factor_levels = [
|
|
|
630 |
{'min': 0.4, 'max': 0.9, 'levels': [0.4, 0.65, 0.9]},
|
631 |
{'min': 24, 'max': 72, 'levels': [24, 48, 72]}
|
632 |
]
|
633 |
+
y_name = 'AIA_ppm'
|
634 |
# Crear instancia
|
635 |
rsm = RSM_BoxBehnken(factor_names, factor_levels, y_name)
|
636 |
design = rsm.generate_box_behnken_design()
|
|
|
642 |
raise ValueError("Ejemplos solo disponibles para 3 y 4 factores.")
|
643 |
else:
|
644 |
# Cargar según la entrada del usuario
|
645 |
+
factor_names = []
|
646 |
+
factor_levels = []
|
647 |
+
for i in range(n_factors):
|
648 |
+
name = factor_inputs[i]['name']
|
649 |
+
min_val = factor_inputs[i]['min']
|
650 |
+
max_val = factor_inputs[i]['max']
|
651 |
+
factor_names.append(name)
|
652 |
+
factor_levels.append({'min': min_val, 'max': max_val, 'levels': [min_val, (min_val + max_val) / 2, max_val]})
|
653 |
# Crear instancia
|
654 |
rsm = RSM_BoxBehnken(factor_names, factor_levels, y_name)
|
655 |
design = rsm.generate_box_behnken_design()
|
656 |
return rsm, design
|
657 |
except Exception as e:
|
658 |
+
print(f"Error al cargar el diseño: {str(e)}")
|
659 |
return None, None
|
660 |
|
661 |
def fit_and_optimize(rsm, response_values):
|
|
|
676 |
rsm.generate_all_plots()
|
677 |
|
678 |
# Formatear la ecuación para que se vea mejor en Markdown
|
679 |
+
equation_formatted = equation.replace(" + ", "<br>+ ").replace("** 2", "^2").replace("*", " × ")
|
680 |
equation_formatted = f"### Ecuación del Modelo Simplificado:<br>{equation_formatted}"
|
681 |
|
682 |
# Guardar las tablas en Excel temporal
|
|
|
749 |
factor_inputs = []
|
750 |
for i in range(6):
|
751 |
with gr.Row():
|
752 |
+
factor_name = gr.Textbox(label=f"Factor {i+1} Nombre", placeholder=f"Nombre del Factor {i+1}", value=f"Factor_{i+1}")
|
753 |
factor_min = gr.Number(label=f"Factor {i+1} Min", value=0.0)
|
754 |
factor_max = gr.Number(label=f"Factor {i+1} Max", value=1.0)
|
755 |
factor_inputs.append({'name': factor_name, 'min': factor_min, 'max': factor_max})
|
|
|
764 |
gr.Markdown("### Diseño Box-Behnken")
|
765 |
design_output = gr.Dataframe(
|
766 |
headers=None,
|
767 |
+
label="Diseño Generado (Completa la Columna de Respuestas)",
|
768 |
interactive=True
|
769 |
)
|
770 |
submit_response_button = gr.Button("✅ Enviar Respuestas")
|
|
|
809 |
with gr.Row():
|
810 |
download_plot_button = gr.DownloadButton("💾 Descargar Gráfico Actual (PNG)")
|
811 |
download_all_plots_button = gr.DownloadButton("💾 Descargar Todos los Gráficos (ZIP)")
|
812 |
+
|
|
|
|
|
|
|
|
|
|
|
813 |
# --- Funciones de la Interfaz ---
|
814 |
|
815 |
+
def handle_load_design_wrapper(n_factors, factor_inputs, y_name, load_example):
|
816 |
"""
|
817 |
+
Wrapper para manejar la carga del diseño Box-Behnken.
|
818 |
"""
|
819 |
+
# Extraer los valores de los inputs
|
820 |
+
factor_details = []
|
821 |
+
for i in range(6):
|
822 |
+
name = factor_inputs[i]['name'].value
|
823 |
+
min_val = factor_inputs[i]['min'].value
|
824 |
+
max_val = factor_inputs[i]['max'].value
|
825 |
+
factor_details.append({'name': name, 'min': min_val, 'max': max_val})
|
826 |
+
# Generar el diseño
|
827 |
+
return handle_load_design(n_factors, factor_details, y_name, load_example)
|
828 |
+
|
829 |
+
def handle_submit_response(rsm, design_df):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
830 |
"""
|
831 |
+
Obtiene las respuestas ingresadas por el usuario y realiza el análisis.
|
832 |
"""
|
833 |
+
try:
|
834 |
+
# Obtener las respuestas de la última columna (AIA_ppm)
|
835 |
+
response_values = design_df[rsm.y_name].tolist()
|
836 |
+
return fit_and_optimize(rsm, response_values)
|
837 |
+
except Exception as e:
|
838 |
+
print(f"Error al procesar las respuestas: {str(e)}")
|
839 |
+
return [None]*12
|
840 |
|
841 |
# Cargar Diseño
|
842 |
load_button.click(
|
843 |
+
fn=handle_load_design_wrapper,
|
844 |
+
inputs=[n_factors_input, factor_inputs, y_name_input, load_example_checkbox],
|
|
|
|
|
|
|
845 |
outputs=[gr.State(), design_output]
|
846 |
)
|
847 |
+
|
848 |
+
# Enviar Respuestas y Realizar Análisis
|
849 |
submit_response_button.click(
|
850 |
+
fn=handle_submit_response,
|
851 |
inputs=[gr.State(), design_output],
|
852 |
outputs=[
|
853 |
model_completo_output,
|
|
|
861 |
anova_table_output,
|
862 |
download_all_plots_button,
|
863 |
download_excel_button,
|
864 |
+
gr.State() # Para tables_dict
|
865 |
]
|
866 |
)
|
867 |
|
868 |
+
# Navegación de Gráficos (Simplificada)
|
869 |
+
current_plot_state = gr.State(0)
|
870 |
+
|
871 |
+
def get_current_plot(rsm, current_index):
|
872 |
+
if not rsm.all_figures:
|
873 |
+
return None, "No hay gráficos disponibles.", current_index
|
874 |
+
selected_fig = rsm.all_figures[current_index]
|
875 |
+
plot_info_text = f"Gráfico {current_index + 1} de {len(rsm.all_figures)}"
|
876 |
+
return selected_fig, plot_info_text, current_index
|
877 |
+
|
878 |
+
def navigate_plot(direction, current_index, rsm):
|
879 |
+
if not rsm.all_figures:
|
880 |
+
return None, "No hay gráficos disponibles.", current_index
|
881 |
+
if direction == 'left':
|
882 |
+
new_index = (current_index - 1) % len(rsm.all_figures)
|
883 |
+
elif direction == 'right':
|
884 |
+
new_index = (current_index + 1) % len(rsm.all_figures)
|
885 |
+
else:
|
886 |
+
new_index = current_index
|
887 |
+
selected_fig = rsm.all_figures[new_index]
|
888 |
+
plot_info_text = f"Gráfico {new_index + 1} de {len(rsm.all_figures)}"
|
889 |
+
return selected_fig, plot_info_text, new_index
|
890 |
+
|
891 |
+
# Navegación de Gráficos
|
892 |
+
left_button.click(
|
893 |
+
fn=navigate_plot,
|
894 |
+
inputs=[gr.ButtonValue(left_button), current_plot_state, gr.State()],
|
895 |
+
outputs=[rsm_plot_output, plot_info, current_plot_state]
|
896 |
+
)
|
897 |
+
right_button.click(
|
898 |
+
fn=navigate_plot,
|
899 |
+
inputs=[gr.ButtonValue(right_button), current_plot_state, gr.State()],
|
900 |
+
outputs=[rsm_plot_output, plot_info, current_plot_state]
|
901 |
+
)
|
902 |
+
|
903 |
+
# Descargar Gráfico Actual
|
904 |
+
download_plot_button.click(
|
905 |
+
fn=lambda rsm, current_index: rsm.save_fig_to_bytes(rsm.all_figures[current_index]) if rsm and rsm.all_figures else None,
|
906 |
+
inputs=[gr.State(), current_plot_state],
|
907 |
+
outputs=download_plot_button
|
908 |
)
|
909 |
|
910 |
# Descargar Todos los Gráficos en ZIP
|
911 |
download_all_plots_button.click(
|
912 |
+
fn=lambda rsm: rsm.save_figures_to_zip() if rsm else None,
|
913 |
+
inputs=[gr.State()],
|
914 |
+
outputs=download_all_plots_button
|
915 |
+
)
|
916 |
+
|
917 |
+
# Descargar Tablas en Excel
|
918 |
+
download_excel_button.click(
|
919 |
+
fn=lambda excel_path: (excel_path, None) if excel_path else (None, None),
|
920 |
+
inputs=[gr.State()],
|
921 |
+
outputs=[download_excel_button, None]
|
922 |
)
|
923 |
|
924 |
# Descargar Tablas en Word
|
925 |
download_word_button.click(
|
926 |
+
fn=lambda rsm_instance, tables_dict: export_word(rsm_instance, tables_dict) if rsm_instance and tables_dict else None,
|
927 |
inputs=[gr.State(), gr.State()],
|
928 |
outputs=[download_word_button]
|
929 |
)
|
930 |
+
|
931 |
return demo
|
932 |
|
933 |
# --- Función Principal ---
|