Update app.py
Browse files
app.py
CHANGED
@@ -16,16 +16,6 @@ class RSM_BoxBehnken:
|
|
16 |
def __init__(self, data, x1_name, x2_name, x3_name, y_name, x1_levels, x2_levels, x3_levels):
|
17 |
"""
|
18 |
Inicializa la clase con los datos del diseño Box-Behnken.
|
19 |
-
|
20 |
-
Args:
|
21 |
-
data (pd.DataFrame): DataFrame con los datos del experimento.
|
22 |
-
x1_name (str): Nombre de la primera variable independiente.
|
23 |
-
x2_name (str): Nombre de la segunda variable independiente.
|
24 |
-
x3_name (str): Nombre de la tercera variable independiente.
|
25 |
-
y_name (str): Nombre de la variable dependiente.
|
26 |
-
x1_levels (list): Niveles de la primera variable independiente.
|
27 |
-
x2_levels (list): Niveles de la segunda variable independiente.
|
28 |
-
x3_levels (list): Niveles de la tercera variable independiente.
|
29 |
"""
|
30 |
self.data = data.copy()
|
31 |
self.model = None
|
@@ -46,12 +36,6 @@ class RSM_BoxBehnken:
|
|
46 |
def get_levels(self, variable_name):
|
47 |
"""
|
48 |
Obtiene los niveles para una variable específica.
|
49 |
-
|
50 |
-
Args:
|
51 |
-
variable_name (str): Nombre de la variable.
|
52 |
-
|
53 |
-
Returns:
|
54 |
-
list: Niveles de la variable.
|
55 |
"""
|
56 |
if variable_name == self.x1_name:
|
57 |
return self.x1_levels
|
@@ -88,9 +72,6 @@ class RSM_BoxBehnken:
|
|
88 |
def optimize(self, method='Nelder-Mead'):
|
89 |
"""
|
90 |
Encuentra los niveles óptimos de los factores para maximizar la respuesta usando el modelo simplificado.
|
91 |
-
|
92 |
-
Args:
|
93 |
-
method (str): Método de optimización a utilizar (por defecto, 'Nelder-Mead').
|
94 |
"""
|
95 |
if self.model_simplified is None:
|
96 |
print("Error: Ajusta el modelo simplificado primero.")
|
@@ -127,13 +108,6 @@ class RSM_BoxBehnken:
|
|
127 |
def plot_rsm_individual(self, fixed_variable, fixed_level):
|
128 |
"""
|
129 |
Genera un gráfico de superficie de respuesta (RSM) individual para una configuración específica.
|
130 |
-
|
131 |
-
Args:
|
132 |
-
fixed_variable (str): Nombre de la variable a mantener fija.
|
133 |
-
fixed_level (float): Nivel al que se fija la variable (en unidades naturales).
|
134 |
-
|
135 |
-
Returns:
|
136 |
-
go.Figure: Objeto de figura de Plotly.
|
137 |
"""
|
138 |
if self.model_simplified is None:
|
139 |
print("Error: Ajusta el modelo simplificado primero.")
|
@@ -242,12 +216,6 @@ class RSM_BoxBehnken:
|
|
242 |
"""
|
243 |
Define las unidades de las variables para etiquetas.
|
244 |
Puedes personalizar este método según tus necesidades.
|
245 |
-
|
246 |
-
Args:
|
247 |
-
variable_name (str): Nombre de la variable.
|
248 |
-
|
249 |
-
Returns:
|
250 |
-
str: Unidades de la variable.
|
251 |
"""
|
252 |
units = {
|
253 |
'Glucosa': 'g/L',
|
@@ -296,10 +264,6 @@ class RSM_BoxBehnken:
|
|
296 |
"""
|
297 |
Genera un diagrama de Pareto para los efectos estandarizados de un modelo,
|
298 |
incluyendo la línea de significancia.
|
299 |
-
|
300 |
-
Args:
|
301 |
-
model: Modelo ajustado de statsmodels.
|
302 |
-
title (str): Título del gráfico.
|
303 |
"""
|
304 |
# Calcular los efectos estandarizados
|
305 |
tvalues = model.tvalues[1:] # Excluir la Intercept
|
@@ -512,9 +476,6 @@ class RSM_BoxBehnken:
|
|
512 |
def save_figures_to_zip(self):
|
513 |
"""
|
514 |
Guarda todas las figuras almacenadas en self.all_figures a un archivo ZIP en memoria.
|
515 |
-
|
516 |
-
Returns:
|
517 |
-
bytes: Bytes del archivo ZIP.
|
518 |
"""
|
519 |
if not self.all_figures:
|
520 |
return None
|
@@ -530,12 +491,6 @@ class RSM_BoxBehnken:
|
|
530 |
def save_fig_to_bytes(self, fig):
|
531 |
"""
|
532 |
Convierte una figura Plotly a bytes en formato PNG.
|
533 |
-
|
534 |
-
Args:
|
535 |
-
fig (go.Figure): Figura de Plotly.
|
536 |
-
|
537 |
-
Returns:
|
538 |
-
bytes: Bytes de la imagen PNG.
|
539 |
"""
|
540 |
return fig.to_image(format="png")
|
541 |
|
@@ -544,19 +499,6 @@ class RSM_BoxBehnken:
|
|
544 |
def load_data(x1_name, x2_name, x3_name, y_name, x1_levels_str, x2_levels_str, x3_levels_str, data_str):
|
545 |
"""
|
546 |
Carga los datos del diseño Box-Behnken desde cajas de texto y crea la instancia de RSM_BoxBehnken.
|
547 |
-
|
548 |
-
Args:
|
549 |
-
x1_name (str): Nombre de la primera variable independiente.
|
550 |
-
x2_name (str): Nombre de la segunda variable independiente.
|
551 |
-
x3_name (str): Nombre de la tercera variable independiente.
|
552 |
-
y_name (str): Nombre de la variable dependiente.
|
553 |
-
x1_levels_str (str): Niveles de la primera variable, separados por comas.
|
554 |
-
x2_levels_str (str): Niveles de la segunda variable, separados por comas.
|
555 |
-
x3_levels_str (str): Niveles de la tercera variable, separados por comas.
|
556 |
-
data_str (str): Datos del experimento en formato CSV, separados por comas.
|
557 |
-
|
558 |
-
Returns:
|
559 |
-
tuple: (pd.DataFrame, str, str, str, str, list, list, list, gr.update)
|
560 |
"""
|
561 |
try:
|
562 |
# Convertir los niveles a listas de números
|
@@ -627,14 +569,6 @@ def show_plot(all_figures, current_index):
|
|
627 |
def navigate_plot(direction, current_index, all_figures):
|
628 |
"""
|
629 |
Navega entre los gráficos.
|
630 |
-
|
631 |
-
Args:
|
632 |
-
direction (str): 'left' o 'right'.
|
633 |
-
current_index (int): Índice actual.
|
634 |
-
all_figures (list): Lista de todas las figuras.
|
635 |
-
|
636 |
-
Returns:
|
637 |
-
tuple: (gr.Figure, str, int)
|
638 |
"""
|
639 |
if not all_figures:
|
640 |
return None, "No hay gráficos disponibles.", current_index
|
@@ -654,58 +588,31 @@ def navigate_plot(direction, current_index, all_figures):
|
|
654 |
def download_current_plot(all_figures, current_index):
|
655 |
"""
|
656 |
Descarga la figura actual como PNG.
|
657 |
-
|
658 |
-
Args:
|
659 |
-
all_figures (list): Lista de figuras.
|
660 |
-
current_index (int): Índice de la figura actual.
|
661 |
-
|
662 |
-
Returns:
|
663 |
-
str: Ruta del archivo PNG temporal.
|
664 |
"""
|
665 |
if not all_figures:
|
666 |
-
return "grafico_actual.png"
|
667 |
fig = all_figures[current_index]
|
668 |
img_bytes = rsm.save_fig_to_bytes(fig)
|
669 |
-
|
670 |
-
|
671 |
-
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
|
672 |
-
temp_file.write(img_bytes)
|
673 |
-
temp_file.close()
|
674 |
-
|
675 |
-
return temp_file.name
|
676 |
|
677 |
def download_all_plots_zip(all_figures):
|
678 |
"""
|
679 |
Descarga todas las figuras en un archivo ZIP.
|
680 |
-
|
681 |
-
Args:
|
682 |
-
all_figures (list): Lista de figuras.
|
683 |
-
|
684 |
-
Returns:
|
685 |
-
str: Ruta del archivo ZIP temporal.
|
686 |
"""
|
687 |
zip_bytes = rsm.save_figures_to_zip()
|
688 |
if zip_bytes:
|
689 |
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
690 |
zip_filename = f"Graficos_RSM_{timestamp}.zip"
|
691 |
-
|
692 |
-
|
693 |
-
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".zip")
|
694 |
-
temp_file.write(zip_bytes)
|
695 |
-
temp_file.close()
|
696 |
-
|
697 |
-
return temp_file.name
|
698 |
-
return "Graficos_RSM.zip" # Ruta predeterminada en caso de error
|
699 |
|
700 |
def download_all_tables_excel():
|
701 |
"""
|
702 |
Descarga todas las tablas en un archivo Excel con múltiples hojas.
|
703 |
-
|
704 |
-
Returns:
|
705 |
-
str: Ruta del archivo Excel temporal.
|
706 |
"""
|
707 |
if 'rsm' not in globals():
|
708 |
-
return "Tablas_RSM.xlsx"
|
709 |
|
710 |
tables = rsm.get_all_tables()
|
711 |
excel_buffer = io.BytesIO()
|
@@ -713,16 +620,12 @@ def download_all_tables_excel():
|
|
713 |
for sheet_name, table in tables.items():
|
714 |
table.to_excel(writer, sheet_name=sheet_name, index=False)
|
715 |
excel_buffer.seek(0)
|
716 |
-
|
717 |
-
# Crear un archivo temporal para el Excel
|
718 |
-
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx")
|
719 |
-
temp_file.write(excel_buffer.read())
|
720 |
-
temp_file.close()
|
721 |
|
722 |
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
723 |
excel_filename = f"Tablas_RSM_{timestamp}.xlsx"
|
724 |
|
725 |
-
return
|
726 |
|
727 |
# --- Crear la interfaz de Gradio ---
|
728 |
|
@@ -793,7 +696,8 @@ with gr.Blocks() as demo:
|
|
793 |
download_plot_button = gr.DownloadButton("Descargar Gráfico Actual (PNG)")
|
794 |
download_all_plots_button = gr.DownloadButton("Descargar Todos los Gráficos (ZIP)")
|
795 |
current_index_state = gr.State(0) # Estado para el índice actual
|
796 |
-
|
|
|
797 |
# Cargar datos
|
798 |
load_button.click(
|
799 |
load_data,
|
@@ -815,41 +719,40 @@ with gr.Blocks() as demo:
|
|
815 |
prediction_table_output,
|
816 |
contribution_table_output,
|
817 |
anova_table_output,
|
818 |
-
|
819 |
-
gr.State() # current_index
|
820 |
]
|
821 |
)
|
822 |
|
823 |
# Generar y mostrar el primer gráfico
|
824 |
plot_button.click(
|
825 |
lambda all_figures: show_plot(all_figures, 0),
|
826 |
-
inputs=[
|
827 |
outputs=[rsm_plot_output, plot_info, current_index_state]
|
828 |
)
|
829 |
|
830 |
# Navegación de gráficos
|
831 |
left_button.click(
|
832 |
lambda current_index, all_figures: navigate_plot('left', current_index, all_figures),
|
833 |
-
inputs=[current_index_state,
|
834 |
outputs=[rsm_plot_output, plot_info, current_index_state]
|
835 |
)
|
836 |
right_button.click(
|
837 |
lambda current_index, all_figures: navigate_plot('right', current_index, all_figures),
|
838 |
-
inputs=[current_index_state,
|
839 |
outputs=[rsm_plot_output, plot_info, current_index_state]
|
840 |
)
|
841 |
|
842 |
# Descargar gráfico actual
|
843 |
download_plot_button.click(
|
844 |
download_current_plot,
|
845 |
-
inputs=[
|
846 |
outputs=[download_plot_button]
|
847 |
)
|
848 |
|
849 |
# Descargar todos los gráficos en ZIP
|
850 |
download_all_plots_button.click(
|
851 |
download_all_plots_zip,
|
852 |
-
inputs=[
|
853 |
outputs=[download_all_plots_button]
|
854 |
)
|
855 |
|
|
|
16 |
def __init__(self, data, x1_name, x2_name, x3_name, y_name, x1_levels, x2_levels, x3_levels):
|
17 |
"""
|
18 |
Inicializa la clase con los datos del diseño Box-Behnken.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
"""
|
20 |
self.data = data.copy()
|
21 |
self.model = None
|
|
|
36 |
def get_levels(self, variable_name):
|
37 |
"""
|
38 |
Obtiene los niveles para una variable específica.
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
"""
|
40 |
if variable_name == self.x1_name:
|
41 |
return self.x1_levels
|
|
|
72 |
def optimize(self, method='Nelder-Mead'):
|
73 |
"""
|
74 |
Encuentra los niveles óptimos de los factores para maximizar la respuesta usando el modelo simplificado.
|
|
|
|
|
|
|
75 |
"""
|
76 |
if self.model_simplified is None:
|
77 |
print("Error: Ajusta el modelo simplificado primero.")
|
|
|
108 |
def plot_rsm_individual(self, fixed_variable, fixed_level):
|
109 |
"""
|
110 |
Genera un gráfico de superficie de respuesta (RSM) individual para una configuración específica.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
"""
|
112 |
if self.model_simplified is None:
|
113 |
print("Error: Ajusta el modelo simplificado primero.")
|
|
|
216 |
"""
|
217 |
Define las unidades de las variables para etiquetas.
|
218 |
Puedes personalizar este método según tus necesidades.
|
|
|
|
|
|
|
|
|
|
|
|
|
219 |
"""
|
220 |
units = {
|
221 |
'Glucosa': 'g/L',
|
|
|
264 |
"""
|
265 |
Genera un diagrama de Pareto para los efectos estandarizados de un modelo,
|
266 |
incluyendo la línea de significancia.
|
|
|
|
|
|
|
|
|
267 |
"""
|
268 |
# Calcular los efectos estandarizados
|
269 |
tvalues = model.tvalues[1:] # Excluir la Intercept
|
|
|
476 |
def save_figures_to_zip(self):
|
477 |
"""
|
478 |
Guarda todas las figuras almacenadas en self.all_figures a un archivo ZIP en memoria.
|
|
|
|
|
|
|
479 |
"""
|
480 |
if not self.all_figures:
|
481 |
return None
|
|
|
491 |
def save_fig_to_bytes(self, fig):
|
492 |
"""
|
493 |
Convierte una figura Plotly a bytes en formato PNG.
|
|
|
|
|
|
|
|
|
|
|
|
|
494 |
"""
|
495 |
return fig.to_image(format="png")
|
496 |
|
|
|
499 |
def load_data(x1_name, x2_name, x3_name, y_name, x1_levels_str, x2_levels_str, x3_levels_str, data_str):
|
500 |
"""
|
501 |
Carga los datos del diseño Box-Behnken desde cajas de texto y crea la instancia de RSM_BoxBehnken.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
502 |
"""
|
503 |
try:
|
504 |
# Convertir los niveles a listas de números
|
|
|
569 |
def navigate_plot(direction, current_index, all_figures):
|
570 |
"""
|
571 |
Navega entre los gráficos.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
572 |
"""
|
573 |
if not all_figures:
|
574 |
return None, "No hay gráficos disponibles.", current_index
|
|
|
588 |
def download_current_plot(all_figures, current_index):
|
589 |
"""
|
590 |
Descarga la figura actual como PNG.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
591 |
"""
|
592 |
if not all_figures:
|
593 |
+
return (None, "grafico_actual.png")
|
594 |
fig = all_figures[current_index]
|
595 |
img_bytes = rsm.save_fig_to_bytes(fig)
|
596 |
+
filename = f"Grafico_RSM_{current_index + 1}.png"
|
597 |
+
return (img_bytes, filename)
|
|
|
|
|
|
|
|
|
|
|
598 |
|
599 |
def download_all_plots_zip(all_figures):
|
600 |
"""
|
601 |
Descarga todas las figuras en un archivo ZIP.
|
|
|
|
|
|
|
|
|
|
|
|
|
602 |
"""
|
603 |
zip_bytes = rsm.save_figures_to_zip()
|
604 |
if zip_bytes:
|
605 |
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
606 |
zip_filename = f"Graficos_RSM_{timestamp}.zip"
|
607 |
+
return (zip_bytes, zip_filename)
|
608 |
+
return (None, "Graficos_RSM.zip") # Nombre por defecto
|
|
|
|
|
|
|
|
|
|
|
|
|
609 |
|
610 |
def download_all_tables_excel():
|
611 |
"""
|
612 |
Descarga todas las tablas en un archivo Excel con múltiples hojas.
|
|
|
|
|
|
|
613 |
"""
|
614 |
if 'rsm' not in globals():
|
615 |
+
return (None, "Tablas_RSM.xlsx")
|
616 |
|
617 |
tables = rsm.get_all_tables()
|
618 |
excel_buffer = io.BytesIO()
|
|
|
620 |
for sheet_name, table in tables.items():
|
621 |
table.to_excel(writer, sheet_name=sheet_name, index=False)
|
622 |
excel_buffer.seek(0)
|
623 |
+
excel_bytes = excel_buffer.read()
|
|
|
|
|
|
|
|
|
624 |
|
625 |
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
626 |
excel_filename = f"Tablas_RSM_{timestamp}.xlsx"
|
627 |
|
628 |
+
return (excel_bytes, excel_filename)
|
629 |
|
630 |
# --- Crear la interfaz de Gradio ---
|
631 |
|
|
|
696 |
download_plot_button = gr.DownloadButton("Descargar Gráfico Actual (PNG)")
|
697 |
download_all_plots_button = gr.DownloadButton("Descargar Todos los Gráficos (ZIP)")
|
698 |
current_index_state = gr.State(0) # Estado para el índice actual
|
699 |
+
all_figures_state = gr.State([]) # Estado para todas las figuras
|
700 |
+
|
701 |
# Cargar datos
|
702 |
load_button.click(
|
703 |
load_data,
|
|
|
719 |
prediction_table_output,
|
720 |
contribution_table_output,
|
721 |
anova_table_output,
|
722 |
+
all_figures_state # Devuelve todas las figuras generadas
|
|
|
723 |
]
|
724 |
)
|
725 |
|
726 |
# Generar y mostrar el primer gráfico
|
727 |
plot_button.click(
|
728 |
lambda all_figures: show_plot(all_figures, 0),
|
729 |
+
inputs=[all_figures_state],
|
730 |
outputs=[rsm_plot_output, plot_info, current_index_state]
|
731 |
)
|
732 |
|
733 |
# Navegación de gráficos
|
734 |
left_button.click(
|
735 |
lambda current_index, all_figures: navigate_plot('left', current_index, all_figures),
|
736 |
+
inputs=[current_index_state, all_figures_state],
|
737 |
outputs=[rsm_plot_output, plot_info, current_index_state]
|
738 |
)
|
739 |
right_button.click(
|
740 |
lambda current_index, all_figures: navigate_plot('right', current_index, all_figures),
|
741 |
+
inputs=[current_index_state, all_figures_state],
|
742 |
outputs=[rsm_plot_output, plot_info, current_index_state]
|
743 |
)
|
744 |
|
745 |
# Descargar gráfico actual
|
746 |
download_plot_button.click(
|
747 |
download_current_plot,
|
748 |
+
inputs=[all_figures_state, current_index_state],
|
749 |
outputs=[download_plot_button]
|
750 |
)
|
751 |
|
752 |
# Descargar todos los gráficos en ZIP
|
753 |
download_all_plots_button.click(
|
754 |
download_all_plots_zip,
|
755 |
+
inputs=[all_figures_state],
|
756 |
outputs=[download_all_plots_button]
|
757 |
)
|
758 |
|