Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -69,7 +69,7 @@ class RSM_BoxBehnken:
|
|
| 69 |
Ajusta el modelo de segundo orden a los datos, eliminando términos no significativos.
|
| 70 |
"""
|
| 71 |
formula = f'{self.y_name} ~ {self.x1_name} + {self.x2_name} + ' \
|
| 72 |
-
f'I({self.x1_name}**2) + I({self.x2_name}**2) + I({self.x3_name}**2)'
|
| 73 |
self.model_simplified = smf.ols(formula, data=self.data).fit()
|
| 74 |
print("\nModelo Simplificado:")
|
| 75 |
print(self.model_simplified.summary())
|
|
@@ -121,7 +121,7 @@ class RSM_BoxBehnken:
|
|
| 121 |
|
| 122 |
# Determinar las variables que varían y sus niveles naturales
|
| 123 |
varying_variables = [var for var in [self.x1_name, self.x2_name, self.x3_name] if var != fixed_variable]
|
| 124 |
-
|
| 125 |
# Establecer los niveles naturales para las variables que varían
|
| 126 |
x_natural_levels = self.get_levels(varying_variables[0])
|
| 127 |
y_natural_levels = self.get_levels(varying_variables[1])
|
|
@@ -224,10 +224,10 @@ class RSM_BoxBehnken:
|
|
| 224 |
Puedes personalizar este método según tus necesidades.
|
| 225 |
"""
|
| 226 |
units = {
|
| 227 |
-
'
|
| 228 |
-
'
|
| 229 |
-
'
|
| 230 |
-
'
|
| 231 |
}
|
| 232 |
return units.get(variable_name, '')
|
| 233 |
|
|
@@ -242,11 +242,11 @@ class RSM_BoxBehnken:
|
|
| 242 |
|
| 243 |
self.all_figures = [] # Resetear la lista de figuras
|
| 244 |
|
| 245 |
-
# Niveles naturales para graficar
|
| 246 |
levels_to_plot_natural = {
|
| 247 |
-
self.x1_name: self.
|
| 248 |
-
self.x2_name: self.
|
| 249 |
-
self.x3_name: self.
|
| 250 |
}
|
| 251 |
|
| 252 |
# Generar y almacenar gráficos individuales
|
|
@@ -361,7 +361,7 @@ class RSM_BoxBehnken:
|
|
| 361 |
'Suma de Cuadrados': [],
|
| 362 |
'% Contribución': []
|
| 363 |
})
|
| 364 |
-
|
| 365 |
# Calcular porcentaje de contribución para cada factor
|
| 366 |
for index, row in anova_table.iterrows():
|
| 367 |
if index != 'Residual':
|
|
@@ -372,7 +372,7 @@ class RSM_BoxBehnken:
|
|
| 372 |
factor_name = f'{self.x2_name}^2'
|
| 373 |
elif factor_name == f'I({self.x3_name} ** 2)':
|
| 374 |
factor_name = f'{self.x3_name}^2'
|
| 375 |
-
|
| 376 |
ss_factor = row['sum_sq']
|
| 377 |
contribution_percentage = (ss_factor / ss_total) * 100
|
| 378 |
|
|
@@ -433,7 +433,7 @@ class RSM_BoxBehnken:
|
|
| 433 |
# 10. Cuadrados medios
|
| 434 |
ms_regression = ss_regression / df_regression
|
| 435 |
ms_residual = ss_residual / df_residual
|
| 436 |
-
ms_lack_of_fit =
|
| 437 |
ms_pure_error = ss_pure_error / df_pure_error if not np.isnan(ss_pure_error) else np.nan
|
| 438 |
|
| 439 |
# 11. Estadístico F y valor p para la falta de ajuste
|
|
@@ -449,7 +449,7 @@ class RSM_BoxBehnken:
|
|
| 449 |
'F': [np.nan, np.nan, f_lack_of_fit, np.nan, np.nan],
|
| 450 |
'Valor p': [np.nan, np.nan, p_lack_of_fit, np.nan, np.nan]
|
| 451 |
})
|
| 452 |
-
|
| 453 |
# Calcular la suma de cuadrados y grados de libertad para la curvatura
|
| 454 |
ss_curvature = anova_reduced['sum_sq'][f'I({self.x1_name} ** 2)'] + anova_reduced['sum_sq'][f'I({self.x2_name} ** 2)'] + anova_reduced['sum_sq'][f'I({self.x3_name} ** 2)']
|
| 455 |
df_curvature = 3
|
|
@@ -459,7 +459,7 @@ class RSM_BoxBehnken:
|
|
| 459 |
|
| 460 |
# Reorganizar las filas para que la curvatura aparezca después de la regresión
|
| 461 |
detailed_anova_table = detailed_anova_table.reindex([0, 5, 1, 2, 3, 4])
|
| 462 |
-
|
| 463 |
# Resetear el índice para que sea consecutivo
|
| 464 |
detailed_anova_table = detailed_anova_table.reset_index(drop=True)
|
| 465 |
|
|
@@ -554,7 +554,7 @@ class RSM_BoxBehnken:
|
|
| 554 |
font.size = Pt(12)
|
| 555 |
|
| 556 |
# Título del informe
|
| 557 |
-
titulo = doc.add_heading('Informe de Optimización de Producción de
|
| 558 |
titulo.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
|
| 559 |
|
| 560 |
doc.add_paragraph(f"Fecha: {datetime.now().strftime('%d/%m/%Y %H:%M')}").alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
|
|
@@ -595,37 +595,48 @@ class RSM_BoxBehnken:
|
|
| 595 |
|
| 596 |
# --- Funciones para la Interfaz de Gradio ---
|
| 597 |
|
| 598 |
-
def load_data(
|
| 599 |
"""
|
| 600 |
Carga los datos del diseño Box-Behnken desde cajas de texto y crea la instancia de RSM_BoxBehnken.
|
| 601 |
"""
|
| 602 |
try:
|
| 603 |
-
#
|
| 604 |
-
|
| 605 |
-
|
| 606 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 607 |
|
| 608 |
-
|
| 609 |
-
|
| 610 |
-
|
| 611 |
-
|
| 612 |
-
|
|
|
|
|
|
|
| 613 |
|
| 614 |
-
# Validar que el DataFrame tenga las columnas correctas
|
| 615 |
-
if not all(col in data.columns for col in column_names):
|
| 616 |
-
raise ValueError("El formato de los datos no es correcto.")
|
| 617 |
|
| 618 |
# Crear la instancia de RSM_BoxBehnken
|
| 619 |
global rsm
|
| 620 |
rsm = RSM_BoxBehnken(data, x1_name, x2_name, x3_name, y_name, x1_levels, x2_levels, x3_levels)
|
| 621 |
|
| 622 |
-
return data.round(3),
|
| 623 |
-
|
| 624 |
except Exception as e:
|
| 625 |
# Mostrar mensaje de error
|
| 626 |
error_message = f"Error al cargar los datos: {str(e)}"
|
| 627 |
print(error_message)
|
| 628 |
-
return None,
|
|
|
|
| 629 |
|
| 630 |
def fit_and_optimize_model():
|
| 631 |
if 'rsm' not in globals():
|
|
@@ -639,14 +650,14 @@ def fit_and_optimize_model():
|
|
| 639 |
prediction_table = rsm.generate_prediction_table()
|
| 640 |
contribution_table = rsm.calculate_contribution_percentage()
|
| 641 |
anova_table = rsm.calculate_detailed_anova()
|
| 642 |
-
|
| 643 |
-
# Generar todas las figuras
|
| 644 |
rsm.generate_all_plots()
|
| 645 |
-
|
| 646 |
# Formatear la ecuación para que se vea mejor en Markdown
|
| 647 |
equation_formatted = equation.replace(" + ", "<br>+ ").replace(" ** ", "^").replace("*", " × ")
|
| 648 |
equation_formatted = f"### Ecuación del Modelo Simplificado:<br>{equation_formatted}"
|
| 649 |
-
|
| 650 |
# Guardar las tablas en Excel temporal
|
| 651 |
excel_path = rsm.save_tables_to_excel()
|
| 652 |
|
|
@@ -658,7 +669,7 @@ def fit_and_optimize_model():
|
|
| 658 |
pareto_completo,
|
| 659 |
model_simplificado.summary().as_html(),
|
| 660 |
pareto_simplificado,
|
| 661 |
-
|
| 662 |
optimization_table,
|
| 663 |
prediction_table,
|
| 664 |
contribution_table,
|
|
@@ -680,17 +691,17 @@ def navigate_plot(direction, current_index, all_figures):
|
|
| 680 |
"""
|
| 681 |
if not all_figures:
|
| 682 |
return None, "No hay gráficos disponibles.", current_index
|
| 683 |
-
|
| 684 |
if direction == 'left':
|
| 685 |
new_index = (current_index - 1) % len(all_figures)
|
| 686 |
elif direction == 'right':
|
| 687 |
new_index = (current_index + 1) % len(all_figures)
|
| 688 |
else:
|
| 689 |
new_index = current_index
|
| 690 |
-
|
| 691 |
selected_fig = all_figures[new_index]
|
| 692 |
plot_info_text = f"Gráfico {new_index + 1} de {len(all_figures)}"
|
| 693 |
-
|
| 694 |
return selected_fig, plot_info_text, new_index
|
| 695 |
|
| 696 |
def download_current_plot(all_figures, current_index):
|
|
@@ -702,12 +713,12 @@ def download_current_plot(all_figures, current_index):
|
|
| 702 |
fig = all_figures[current_index]
|
| 703 |
img_bytes = rsm.save_fig_to_bytes(fig)
|
| 704 |
filename = f"Grafico_RSM_{current_index + 1}.png"
|
| 705 |
-
|
| 706 |
# Crear un archivo temporal
|
| 707 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as temp_file:
|
| 708 |
temp_file.write(img_bytes)
|
| 709 |
temp_path = temp_file.name
|
| 710 |
-
|
| 711 |
return temp_path # Retornar solo la ruta
|
| 712 |
|
| 713 |
def download_all_plots_zip():
|
|
@@ -749,39 +760,19 @@ def exportar_word(rsm_instance, tables_dict):
|
|
| 749 |
|
| 750 |
def create_gradio_interface():
|
| 751 |
with gr.Blocks() as demo:
|
| 752 |
-
gr.Markdown("# Optimización de la
|
| 753 |
-
|
| 754 |
with gr.Row():
|
| 755 |
with gr.Column():
|
| 756 |
-
gr.Markdown("## Configuración del
|
| 757 |
-
|
| 758 |
-
|
| 759 |
-
|
| 760 |
-
|
| 761 |
-
x1_levels_input = gr.Textbox(label="Niveles de X1 (separados por comas)", value="1, 3.5, 5.5")
|
| 762 |
-
x2_levels_input = gr.Textbox(label="Niveles de X2 (separados por comas)", value="0.03, 0.2, 0.3")
|
| 763 |
-
x3_levels_input = gr.Textbox(label="Niveles de X3 (separados por comas)", value="0.4, 0.65, 0.9")
|
| 764 |
-
data_input = gr.Textbox(label="Datos del Experimento (formato CSV)", lines=10, value="""1,-1,-1,0,166.594
|
| 765 |
-
2,1,-1,0,177.557
|
| 766 |
-
3,-1,1,0,127.261
|
| 767 |
-
4,1,1,0,147.573
|
| 768 |
-
5,-1,0,-1,188.883
|
| 769 |
-
6,1,0,-1,224.527
|
| 770 |
-
7,-1,0,1,190.238
|
| 771 |
-
8,1,0,1,226.483
|
| 772 |
-
9,0,-1,-1,195.550
|
| 773 |
-
10,0,1,-1,149.493
|
| 774 |
-
11,0,-1,1,187.683
|
| 775 |
-
12,0,1,1,148.621
|
| 776 |
-
13,0,0,0,278.951
|
| 777 |
-
14,0,0,0,297.238
|
| 778 |
-
15,0,0,0,280.896""")
|
| 779 |
-
load_button = gr.Button("Cargar Datos")
|
| 780 |
-
|
| 781 |
with gr.Column():
|
| 782 |
gr.Markdown("## Datos Cargados")
|
| 783 |
data_output = gr.Dataframe(label="Tabla de Datos", interactive=False)
|
| 784 |
-
|
| 785 |
# Sección de análisis visible solo después de cargar los datos
|
| 786 |
with gr.Row(visible=False) as analysis_row:
|
| 787 |
with gr.Column():
|
|
@@ -801,11 +792,11 @@ def create_gradio_interface():
|
|
| 801 |
gr.Markdown("## Descargar Todas las Tablas")
|
| 802 |
download_excel_button = gr.DownloadButton("Descargar Tablas en Excel")
|
| 803 |
download_word_button = gr.DownloadButton("Descargar Tablas en Word")
|
| 804 |
-
|
| 805 |
with gr.Column():
|
| 806 |
gr.Markdown("## Generar Gráficos de Superficie de Respuesta")
|
| 807 |
-
fixed_variable_input = gr.Dropdown(label="Variable Fija", choices=["
|
| 808 |
-
fixed_level_input = gr.Slider(label="Nivel de Variable Fija", minimum
|
| 809 |
plot_button = gr.Button("Generar Gráficos")
|
| 810 |
with gr.Row():
|
| 811 |
left_button = gr.Button("<")
|
|
@@ -817,14 +808,14 @@ def create_gradio_interface():
|
|
| 817 |
download_all_plots_button = gr.DownloadButton("Descargar Todos los Gráficos (ZIP)")
|
| 818 |
current_index_state = gr.State(0) # Estado para el índice actual
|
| 819 |
all_figures_state = gr.State([]) # Estado para todas las figuras
|
| 820 |
-
|
| 821 |
-
# Cargar datos
|
| 822 |
load_button.click(
|
| 823 |
load_data,
|
| 824 |
-
inputs=[
|
| 825 |
-
outputs=[data_output,
|
| 826 |
)
|
| 827 |
-
|
| 828 |
# Ajustar modelo y optimizar
|
| 829 |
fit_button.click(
|
| 830 |
fit_and_optimize_model,
|
|
@@ -843,7 +834,7 @@ def create_gradio_interface():
|
|
| 843 |
download_excel_button # Ruta del Excel de tablas
|
| 844 |
]
|
| 845 |
)
|
| 846 |
-
|
| 847 |
# Generar y mostrar los gráficos
|
| 848 |
plot_button.click(
|
| 849 |
lambda fixed_var, fixed_lvl: (
|
|
@@ -855,7 +846,7 @@ def create_gradio_interface():
|
|
| 855 |
inputs=[fixed_variable_input, fixed_level_input],
|
| 856 |
outputs=[rsm_plot_output, plot_info, current_index_state, all_figures_state]
|
| 857 |
)
|
| 858 |
-
|
| 859 |
# Navegación de gráficos
|
| 860 |
left_button.click(
|
| 861 |
lambda current_index, all_figures: navigate_plot('left', current_index, all_figures),
|
|
@@ -867,46 +858,43 @@ def create_gradio_interface():
|
|
| 867 |
inputs=[current_index_state, all_figures_state],
|
| 868 |
outputs=[rsm_plot_output, plot_info, current_index_state]
|
| 869 |
)
|
| 870 |
-
|
| 871 |
# Descargar gráfico actual
|
| 872 |
download_plot_button.click(
|
| 873 |
download_current_plot,
|
| 874 |
inputs=[all_figures_state, current_index_state],
|
| 875 |
outputs=download_plot_button
|
| 876 |
)
|
| 877 |
-
|
| 878 |
# Descargar todos los gráficos en ZIP
|
| 879 |
download_all_plots_button.click(
|
| 880 |
download_all_plots_zip,
|
| 881 |
inputs=[],
|
| 882 |
outputs=download_all_plots_button
|
| 883 |
)
|
| 884 |
-
|
| 885 |
# Descargar todas las tablas en Excel y Word
|
| 886 |
download_excel_button.click(
|
| 887 |
fn=lambda: download_all_tables_excel(),
|
| 888 |
inputs=[],
|
| 889 |
outputs=download_excel_button
|
| 890 |
)
|
| 891 |
-
|
| 892 |
download_word_button.click(
|
| 893 |
fn=lambda: exportar_word(rsm, rsm.get_all_tables()),
|
| 894 |
inputs=[],
|
| 895 |
outputs=download_word_button
|
| 896 |
)
|
| 897 |
-
|
| 898 |
# Ejemplo de uso
|
| 899 |
-
gr.Markdown("##
|
| 900 |
gr.Markdown("""
|
| 901 |
-
1.
|
| 902 |
-
2.
|
| 903 |
-
3.
|
| 904 |
-
4.
|
| 905 |
-
5.
|
| 906 |
-
6.
|
| 907 |
-
7. Navega entre los gráficos usando los botones '<' y '>'.
|
| 908 |
-
8. Descarga el gráfico actual en PNG o descarga todos los gráficos en un ZIP.
|
| 909 |
-
9. Descarga todas las tablas en un archivo Excel o Word con los botones correspondientes.
|
| 910 |
""")
|
| 911 |
|
| 912 |
return demo
|
|
@@ -918,4 +906,4 @@ def main():
|
|
| 918 |
interface.launch(share=True)
|
| 919 |
|
| 920 |
if __name__ == "__main__":
|
| 921 |
-
main()
|
|
|
|
| 69 |
Ajusta el modelo de segundo orden a los datos, eliminando términos no significativos.
|
| 70 |
"""
|
| 71 |
formula = f'{self.y_name} ~ {self.x1_name} + {self.x2_name} + ' \
|
| 72 |
+
f'I({self.x1_name}**2) + I({self.x2_name}**2) + I({self.x3_name}**2)' # Adjusted formula to include x3^2
|
| 73 |
self.model_simplified = smf.ols(formula, data=self.data).fit()
|
| 74 |
print("\nModelo Simplificado:")
|
| 75 |
print(self.model_simplified.summary())
|
|
|
|
| 121 |
|
| 122 |
# Determinar las variables que varían y sus niveles naturales
|
| 123 |
varying_variables = [var for var in [self.x1_name, self.x2_name, self.x3_name] if var != fixed_variable]
|
| 124 |
+
|
| 125 |
# Establecer los niveles naturales para las variables que varían
|
| 126 |
x_natural_levels = self.get_levels(varying_variables[0])
|
| 127 |
y_natural_levels = self.get_levels(varying_variables[1])
|
|
|
|
| 224 |
Puedes personalizar este método según tus necesidades.
|
| 225 |
"""
|
| 226 |
units = {
|
| 227 |
+
'Glucosa_g_L': 'g/L',
|
| 228 |
+
'Proteina_Pescado_g_L': 'g/L',
|
| 229 |
+
'Sulfato_Manganeso_g_L': 'g/L',
|
| 230 |
+
'Abs_600nm': '' # No units for Absorbance
|
| 231 |
}
|
| 232 |
return units.get(variable_name, '')
|
| 233 |
|
|
|
|
| 242 |
|
| 243 |
self.all_figures = [] # Resetear la lista de figuras
|
| 244 |
|
| 245 |
+
# Niveles naturales para graficar - Using levels from the data context, not Box-Behnken design levels.
|
| 246 |
levels_to_plot_natural = {
|
| 247 |
+
self.x1_name: sorted(list(set(self.data[self.x1_name]))), # Using unique values from data
|
| 248 |
+
self.x2_name: sorted(list(set(self.data[self.x2_name]))), # Using unique values from data
|
| 249 |
+
self.x3_name: sorted(list(set(self.data[self.x3_name]))) # Using unique values from data
|
| 250 |
}
|
| 251 |
|
| 252 |
# Generar y almacenar gráficos individuales
|
|
|
|
| 361 |
'Suma de Cuadrados': [],
|
| 362 |
'% Contribución': []
|
| 363 |
})
|
| 364 |
+
|
| 365 |
# Calcular porcentaje de contribución para cada factor
|
| 366 |
for index, row in anova_table.iterrows():
|
| 367 |
if index != 'Residual':
|
|
|
|
| 372 |
factor_name = f'{self.x2_name}^2'
|
| 373 |
elif factor_name == f'I({self.x3_name} ** 2)':
|
| 374 |
factor_name = f'{self.x3_name}^2'
|
| 375 |
+
|
| 376 |
ss_factor = row['sum_sq']
|
| 377 |
contribution_percentage = (ss_factor / ss_total) * 100
|
| 378 |
|
|
|
|
| 433 |
# 10. Cuadrados medios
|
| 434 |
ms_regression = ss_regression / df_regression
|
| 435 |
ms_residual = ss_residual / df_residual
|
| 436 |
+
ms_lack_of_fit = ms_lack_of_fit / df_lack_of_fit if not np.isnan(ss_lack_of_fit) else np.nan
|
| 437 |
ms_pure_error = ss_pure_error / df_pure_error if not np.isnan(ss_pure_error) else np.nan
|
| 438 |
|
| 439 |
# 11. Estadístico F y valor p para la falta de ajuste
|
|
|
|
| 449 |
'F': [np.nan, np.nan, f_lack_of_fit, np.nan, np.nan],
|
| 450 |
'Valor p': [np.nan, np.nan, p_lack_of_fit, np.nan, np.nan]
|
| 451 |
})
|
| 452 |
+
|
| 453 |
# Calcular la suma de cuadrados y grados de libertad para la curvatura
|
| 454 |
ss_curvature = anova_reduced['sum_sq'][f'I({self.x1_name} ** 2)'] + anova_reduced['sum_sq'][f'I({self.x2_name} ** 2)'] + anova_reduced['sum_sq'][f'I({self.x3_name} ** 2)']
|
| 455 |
df_curvature = 3
|
|
|
|
| 459 |
|
| 460 |
# Reorganizar las filas para que la curvatura aparezca después de la regresión
|
| 461 |
detailed_anova_table = detailed_anova_table.reindex([0, 5, 1, 2, 3, 4])
|
| 462 |
+
|
| 463 |
# Resetear el índice para que sea consecutivo
|
| 464 |
detailed_anova_table = detailed_anova_table.reset_index(drop=True)
|
| 465 |
|
|
|
|
| 554 |
font.size = Pt(12)
|
| 555 |
|
| 556 |
# Título del informe
|
| 557 |
+
titulo = doc.add_heading('Informe de Optimización de Producción de Absorbancia', 0) # Changed Title
|
| 558 |
titulo.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
|
| 559 |
|
| 560 |
doc.add_paragraph(f"Fecha: {datetime.now().strftime('%d/%m/%Y %H:%M')}").alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
|
|
|
|
| 595 |
|
| 596 |
# --- Funciones para la Interfaz de Gradio ---
|
| 597 |
|
| 598 |
+
def load_data(data_str): # Modified load_data to only take data_str
|
| 599 |
"""
|
| 600 |
Carga los datos del diseño Box-Behnken desde cajas de texto y crea la instancia de RSM_BoxBehnken.
|
| 601 |
"""
|
| 602 |
try:
|
| 603 |
+
# Use the data dictionary directly
|
| 604 |
+
data_dict = {
|
| 605 |
+
'Tratamiento': ['T1', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7', 'T8', 'T9', 'T10', 'T11', 'T12', 'T13', 'T14', 'T15'] * 3,
|
| 606 |
+
'Tiempo_fermentacion_h': [16] * 15 + [23] * 15 + [40] * 15,
|
| 607 |
+
'pH': [6.02, 5.39, 6.27, 4.82, 6.25, 4.87, 4.76, 4.68, 4.64, 6.35, 4.67, 6.43, 4.58, 4.60, 6.96,
|
| 608 |
+
5.17, 5.95, 6.90, 5.50, 5.08, 4.95, 5.41, 5.52, 4.98, 7.10, 5.36, 6.91, 5.21, 4.66, 7.10,
|
| 609 |
+
5.42, 5.60, 7.36, 5.36, 4.66, 4.93, 5.18, 5.26, 4.92, 7.28, 5.26, 6.84, 5.19, 4.58, 7.07],
|
| 610 |
+
'Abs_600nm': [1.576, 1.474, 1.293, 1.446, 1.537, 1.415, 1.481, 1.419, 1.321, 1.224, 1.459, 0.345, 1.279, 1.181, 0.662,
|
| 611 |
+
1.760, 1.690, 1.485, 1.658, 1.728, 1.594, 1.673, 1.607, 1.531, 1.424, 1.595, 0.344, 1.477, 1.257, 0.660,
|
| 612 |
+
1.932, 1.780, 1.689, 1.876, 1.885, 1.824, 1.913, 1.810, 1.852, 1.694, 1.831, 0.347, 1.752, 1.367, 0.656],
|
| 613 |
+
'Glucosa_g_L': [5,10,0,5,10,5,10,5,10,0,5,0,5,5,0] * 3,
|
| 614 |
+
'Proteina_Pescado_g_L': [1.4,1.4,3.2,3.2,3.2,3.2,3.2,5,5,5,5,0,5,5,0] * 3,
|
| 615 |
+
'Sulfato_Manganeso_g_L': [0.75,0.5,0.75,0.5,0.75,0.5,0.75,0.5,0.25,0.75,0.5,0.25,0.5,0.25,0.5] * 3
|
| 616 |
+
}
|
| 617 |
+
data = pd.DataFrame(data_dict)
|
| 618 |
|
| 619 |
+
x1_name = "Glucosa_g_L"
|
| 620 |
+
x2_name = "Proteina_Pescado_g_L"
|
| 621 |
+
x3_name = "Sulfato_Manganeso_g_L"
|
| 622 |
+
y_name = "Abs_600nm"
|
| 623 |
+
x1_levels = sorted(list(set(data[x1_name]))) # Levels from data
|
| 624 |
+
x2_levels = sorted(list(set(data[x2_name]))) # Levels from data
|
| 625 |
+
x3_levels = sorted(list(set(data[x3_name]))) # Levels from data
|
| 626 |
|
|
|
|
|
|
|
|
|
|
| 627 |
|
| 628 |
# Crear la instancia de RSM_BoxBehnken
|
| 629 |
global rsm
|
| 630 |
rsm = RSM_BoxBehnken(data, x1_name, x2_name, x3_name, y_name, x1_levels, x2_levels, x3_levels)
|
| 631 |
|
| 632 |
+
return data.round(3), gr.update(visible=True) # Removed other outputs, only return data_output and analysis_row
|
| 633 |
+
|
| 634 |
except Exception as e:
|
| 635 |
# Mostrar mensaje de error
|
| 636 |
error_message = f"Error al cargar los datos: {str(e)}"
|
| 637 |
print(error_message)
|
| 638 |
+
return None, gr.update(visible=False) # Removed other outputs, only return data_output and analysis_row
|
| 639 |
+
|
| 640 |
|
| 641 |
def fit_and_optimize_model():
|
| 642 |
if 'rsm' not in globals():
|
|
|
|
| 650 |
prediction_table = rsm.generate_prediction_table()
|
| 651 |
contribution_table = rsm.calculate_contribution_percentage()
|
| 652 |
anova_table = rsm.calculate_detailed_anova()
|
| 653 |
+
|
| 654 |
+
# Generar todas las figuras and store them in rsm.all_figures
|
| 655 |
rsm.generate_all_plots()
|
| 656 |
+
|
| 657 |
# Formatear la ecuación para que se vea mejor en Markdown
|
| 658 |
equation_formatted = equation.replace(" + ", "<br>+ ").replace(" ** ", "^").replace("*", " × ")
|
| 659 |
equation_formatted = f"### Ecuación del Modelo Simplificado:<br>{equation_formatted}"
|
| 660 |
+
|
| 661 |
# Guardar las tablas en Excel temporal
|
| 662 |
excel_path = rsm.save_tables_to_excel()
|
| 663 |
|
|
|
|
| 669 |
pareto_completo,
|
| 670 |
model_simplificado.summary().as_html(),
|
| 671 |
pareto_simplificado,
|
| 672 |
+
equation_output,
|
| 673 |
optimization_table,
|
| 674 |
prediction_table,
|
| 675 |
contribution_table,
|
|
|
|
| 691 |
"""
|
| 692 |
if not all_figures:
|
| 693 |
return None, "No hay gráficos disponibles.", current_index
|
| 694 |
+
|
| 695 |
if direction == 'left':
|
| 696 |
new_index = (current_index - 1) % len(all_figures)
|
| 697 |
elif direction == 'right':
|
| 698 |
new_index = (current_index + 1) % len(all_figures)
|
| 699 |
else:
|
| 700 |
new_index = current_index
|
| 701 |
+
|
| 702 |
selected_fig = all_figures[new_index]
|
| 703 |
plot_info_text = f"Gráfico {new_index + 1} de {len(all_figures)}"
|
| 704 |
+
|
| 705 |
return selected_fig, plot_info_text, new_index
|
| 706 |
|
| 707 |
def download_current_plot(all_figures, current_index):
|
|
|
|
| 713 |
fig = all_figures[current_index]
|
| 714 |
img_bytes = rsm.save_fig_to_bytes(fig)
|
| 715 |
filename = f"Grafico_RSM_{current_index + 1}.png"
|
| 716 |
+
|
| 717 |
# Crear un archivo temporal
|
| 718 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as temp_file:
|
| 719 |
temp_file.write(img_bytes)
|
| 720 |
temp_path = temp_file.name
|
| 721 |
+
|
| 722 |
return temp_path # Retornar solo la ruta
|
| 723 |
|
| 724 |
def download_all_plots_zip():
|
|
|
|
| 760 |
|
| 761 |
def create_gradio_interface():
|
| 762 |
with gr.Blocks() as demo:
|
| 763 |
+
gr.Markdown("# Optimización de la Absorbancia usando RSM") # Changed Title
|
| 764 |
+
|
| 765 |
with gr.Row():
|
| 766 |
with gr.Column():
|
| 767 |
+
gr.Markdown("## Configuración del Análisis") # Changed Section Title
|
| 768 |
+
# Removed input boxes for variable names and levels
|
| 769 |
+
data_input = gr.Textbox(label="Datos del Experimento (formato CSV - Ignored, Data is Hardcoded)", lines=5, interactive=False, value="Data is pre-loaded, ignore input.") # Adjusted Textbox
|
| 770 |
+
load_button = gr.Button("Cargar Datos") # Keep load button for triggering data load but input is ignored
|
| 771 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 772 |
with gr.Column():
|
| 773 |
gr.Markdown("## Datos Cargados")
|
| 774 |
data_output = gr.Dataframe(label="Tabla de Datos", interactive=False)
|
| 775 |
+
|
| 776 |
# Sección de análisis visible solo después de cargar los datos
|
| 777 |
with gr.Row(visible=False) as analysis_row:
|
| 778 |
with gr.Column():
|
|
|
|
| 792 |
gr.Markdown("## Descargar Todas las Tablas")
|
| 793 |
download_excel_button = gr.DownloadButton("Descargar Tablas en Excel")
|
| 794 |
download_word_button = gr.DownloadButton("Descargar Tablas en Word")
|
| 795 |
+
|
| 796 |
with gr.Column():
|
| 797 |
gr.Markdown("## Generar Gráficos de Superficie de Respuesta")
|
| 798 |
+
fixed_variable_input = gr.Dropdown(label="Variable Fija", choices=["Glucosa_g_L", "Proteina_Pescado_g_L", "Sulfato_Manganeso_g_L"], value="Glucosa_g_L") # Updated choices
|
| 799 |
+
fixed_level_input = gr.Slider(label="Nivel de Variable Fija (Natural Units)", minimum=0, maximum=10, step=0.1, value=5.0) # Updated Slider
|
| 800 |
plot_button = gr.Button("Generar Gráficos")
|
| 801 |
with gr.Row():
|
| 802 |
left_button = gr.Button("<")
|
|
|
|
| 808 |
download_all_plots_button = gr.DownloadButton("Descargar Todos los Gráficos (ZIP)")
|
| 809 |
current_index_state = gr.State(0) # Estado para el índice actual
|
| 810 |
all_figures_state = gr.State([]) # Estado para todas las figuras
|
| 811 |
+
|
| 812 |
+
# Cargar datos - Modified load_button click to only take data_input (which is ignored)
|
| 813 |
load_button.click(
|
| 814 |
load_data,
|
| 815 |
+
inputs=[data_input], # Only data_input is now input
|
| 816 |
+
outputs=[data_output, analysis_row] # Removed other outputs, only return data_output and analysis_row
|
| 817 |
)
|
| 818 |
+
|
| 819 |
# Ajustar modelo y optimizar
|
| 820 |
fit_button.click(
|
| 821 |
fit_and_optimize_model,
|
|
|
|
| 834 |
download_excel_button # Ruta del Excel de tablas
|
| 835 |
]
|
| 836 |
)
|
| 837 |
+
|
| 838 |
# Generar y mostrar los gráficos
|
| 839 |
plot_button.click(
|
| 840 |
lambda fixed_var, fixed_lvl: (
|
|
|
|
| 846 |
inputs=[fixed_variable_input, fixed_level_input],
|
| 847 |
outputs=[rsm_plot_output, plot_info, current_index_state, all_figures_state]
|
| 848 |
)
|
| 849 |
+
|
| 850 |
# Navegación de gráficos
|
| 851 |
left_button.click(
|
| 852 |
lambda current_index, all_figures: navigate_plot('left', current_index, all_figures),
|
|
|
|
| 858 |
inputs=[current_index_state, all_figures_state],
|
| 859 |
outputs=[rsm_plot_output, plot_info, current_index_state]
|
| 860 |
)
|
| 861 |
+
|
| 862 |
# Descargar gráfico actual
|
| 863 |
download_plot_button.click(
|
| 864 |
download_current_plot,
|
| 865 |
inputs=[all_figures_state, current_index_state],
|
| 866 |
outputs=download_plot_button
|
| 867 |
)
|
| 868 |
+
|
| 869 |
# Descargar todos los gráficos en ZIP
|
| 870 |
download_all_plots_button.click(
|
| 871 |
download_all_plots_zip,
|
| 872 |
inputs=[],
|
| 873 |
outputs=download_all_plots_button
|
| 874 |
)
|
| 875 |
+
|
| 876 |
# Descargar todas las tablas en Excel y Word
|
| 877 |
download_excel_button.click(
|
| 878 |
fn=lambda: download_all_tables_excel(),
|
| 879 |
inputs=[],
|
| 880 |
outputs=download_excel_button
|
| 881 |
)
|
| 882 |
+
|
| 883 |
download_word_button.click(
|
| 884 |
fn=lambda: exportar_word(rsm, rsm.get_all_tables()),
|
| 885 |
inputs=[],
|
| 886 |
outputs=download_word_button
|
| 887 |
)
|
| 888 |
+
|
| 889 |
# Ejemplo de uso
|
| 890 |
+
gr.Markdown("## Instrucciones:") # Shortened Instructions
|
| 891 |
gr.Markdown("""
|
| 892 |
+
1. Click 'Cargar Datos' para usar los datos precargados.
|
| 893 |
+
2. Click 'Ajustar Modelo y Optimizar'.
|
| 894 |
+
3. Select 'Variable Fija' and 'Nivel de Variable Fija'.
|
| 895 |
+
4. Click 'Generar Gráficos'.
|
| 896 |
+
5. Navigate plots with '<' and '>'.
|
| 897 |
+
6. Download plots and tables as needed.
|
|
|
|
|
|
|
|
|
|
| 898 |
""")
|
| 899 |
|
| 900 |
return demo
|
|
|
|
| 906 |
interface.launch(share=True)
|
| 907 |
|
| 908 |
if __name__ == "__main__":
|
| 909 |
+
main()
|