|
import gradio as gr |
|
import pandas as pd |
|
import numpy as np |
|
import matplotlib.pyplot as plt |
|
import seaborn as sns |
|
from scipy import stats |
|
from datetime import datetime |
|
import docx |
|
from docx.shared import Inches, Pt |
|
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT |
|
import os |
|
|
|
def generar_tabla(n_filas, concentracion_inicial, unidad_medida): |
|
valores_base = [1.00, 0.80, 0.60, 0.40, 0.20, 0.10, 0.05] |
|
|
|
if n_filas <= 7: |
|
solucion_inoculo = valores_base[:n_filas] |
|
agua = [round(1 - x, 2) for x in solucion_inoculo] |
|
else: |
|
solucion_inoculo = valores_base.copy() |
|
ultimo_valor = valores_base[-1] |
|
for _ in range(n_filas - 7): |
|
nuevo_valor = round(ultimo_valor / 2, 3) |
|
solucion_inoculo.append(nuevo_valor) |
|
ultimo_valor = nuevo_valor |
|
agua = [round(1 - x, 3) for x in solucion_inoculo] |
|
|
|
data = { |
|
f"Soluci贸n de in贸culo ({concentracion_inicial} {unidad_medida})": solucion_inoculo, |
|
"H2O": agua |
|
} |
|
df = pd.DataFrame(data) |
|
|
|
nombre_columna = f"Soluci贸n de in贸culo ({concentracion_inicial} {unidad_medida})" |
|
df["Factor de Diluci贸n"] = df[nombre_columna].apply(lambda x: round(1 / x, 2)) |
|
df[f"Concentraci贸n Predicha ({unidad_medida})"] = df["Factor de Diluci贸n"].apply( |
|
lambda x: round(concentracion_inicial / x, 0) |
|
) |
|
|
|
df[f"Concentraci贸n Real ({unidad_medida})"] = None |
|
|
|
return df |
|
|
|
def ajustar_decimales_evento(df, decimales): |
|
df = df.copy() |
|
|
|
col_predicha = [col for col in df.columns if 'Concentraci贸n Predicha' in col][0] |
|
|
|
df[col_predicha] = df[col_predicha].astype(float).round(decimales) |
|
return df |
|
|
|
def generar_datos_sinteticos(df, desviacion_std): |
|
col_predicha = [col for col in df.columns if 'Predicha' in col][0] |
|
col_real = [col for col in df.columns if 'Real' in col][0] |
|
|
|
|
|
valores_predichos = df[col_predicha].astype(float).values |
|
datos_sinteticos = valores_predichos + np.random.normal(0, desviacion_std, size=len(valores_predichos)) |
|
datos_sinteticos = np.maximum(0, datos_sinteticos) |
|
datos_sinteticos = np.round(datos_sinteticos, 2) |
|
|
|
df[col_real] = datos_sinteticos |
|
|
|
return df |
|
|
|
def generar_graficos(df_valid): |
|
col_predicha = [col for col in df_valid.columns if 'Predicha' in col][0] |
|
col_real = [col for col in df_valid.columns if 'Real' in col][0] |
|
|
|
|
|
df_valid[col_predicha] = df_valid[col_predicha].astype(float) |
|
df_valid[col_real] = df_valid[col_real].astype(float) |
|
|
|
|
|
slope, intercept, r_value, p_value, std_err = stats.linregress(df_valid[col_predicha], df_valid[col_real]) |
|
df_valid['Ajuste Lineal'] = intercept + slope * df_valid[col_predicha] |
|
|
|
|
|
sns.set(style="whitegrid") |
|
plt.rcParams.update({'figure.autolayout': True}) |
|
|
|
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6)) |
|
|
|
|
|
sns.scatterplot( |
|
data=df_valid, |
|
x=col_predicha, |
|
y=col_real, |
|
ax=ax1, |
|
color='blue', |
|
s=100, |
|
label='Datos Reales', |
|
marker='o' |
|
) |
|
|
|
|
|
sns.lineplot( |
|
x=df_valid[col_predicha], |
|
y=df_valid['Ajuste Lineal'], |
|
ax=ax1, |
|
color='green', |
|
label='Ajuste Lineal', |
|
linewidth=2 |
|
) |
|
|
|
|
|
min_predicha = df_valid[col_predicha].min() |
|
max_predicha = df_valid[col_predicha].max() |
|
ax1.plot( |
|
[min_predicha, max_predicha], |
|
[min_predicha, max_predicha], |
|
color='red', |
|
linestyle='--', |
|
label='Ideal' |
|
) |
|
|
|
ax1.set_title('Correlaci贸n entre Concentraci贸n Predicha y Real', fontsize=14) |
|
ax1.set_xlabel('Concentraci贸n Predicha', fontsize=12) |
|
ax1.set_ylabel('Concentraci贸n Real', fontsize=12) |
|
|
|
|
|
ax1.annotate( |
|
f'y = {intercept:.2f} + {slope:.2f}x\n$R^2$ = {r_value**2:.4f}', |
|
xy=(0.05, 0.95), |
|
xycoords='axes fraction', |
|
fontsize=12, |
|
backgroundcolor='white', |
|
verticalalignment='top' |
|
) |
|
|
|
|
|
ax1.legend(loc='lower right', fontsize=10) |
|
|
|
|
|
residuos = df_valid[col_real] - df_valid['Ajuste Lineal'] |
|
sns.scatterplot( |
|
data=df_valid, |
|
x=col_predicha, |
|
y=residuos, |
|
ax=ax2, |
|
color='purple', |
|
s=100, |
|
marker='D', |
|
label='Residuos' |
|
) |
|
|
|
ax2.axhline(y=0, color='black', linestyle='--', linewidth=1) |
|
ax2.set_title('Gr谩fico de Residuos', fontsize=14) |
|
ax2.set_xlabel('Concentraci贸n Predicha', fontsize=12) |
|
ax2.set_ylabel('Residuo', fontsize=12) |
|
ax2.legend(loc='upper right', fontsize=10) |
|
|
|
plt.tight_layout() |
|
plt.savefig('grafico.png') |
|
return fig |
|
|
|
def evaluar_calidad_calibracion(df_valid, r_squared, rmse, cv_percent): |
|
|
|
|
|
|
|
def generar_informe_completo(df_valid): |
|
|
|
|
|
|
|
def actualizar_analisis(df): |
|
|
|
|
|
|
|
def exportar_informe_word(df_valid, informe_md): |
|
|
|
|
|
|
|
def exportar_informe_latex(df_valid, informe_md): |
|
|
|
|
|
|
|
def exportar_word(df, informe_md): |
|
|
|
|
|
|
|
def exportar_latex(df, informe_md): |
|
|
|
|
|
|
|
|
|
def cargar_ejemplo_ufc(): |
|
|
|
|
|
|
|
def cargar_ejemplo_od(): |
|
|
|
|
|
|
|
def limpiar_datos(): |
|
|
|
|
|
|
|
def generar_datos_sinteticos_evento(df): |
|
|
|
|
|
|
|
def actualizar_tabla_evento(df, n_filas, concentracion, unidad): |
|
|
|
df_new = generar_tabla(n_filas, concentracion, unidad) |
|
|
|
|
|
col_predicha_new = [col for col in df_new.columns if 'Concentraci贸n Predicha' in col][0] |
|
col_predicha_old = [col for col in df.columns if 'Concentraci贸n Predicha' in col][0] |
|
col_real_new = [col for col in df_new.columns if 'Concentraci贸n Real' in col][0] |
|
col_real_old = [col for col in df.columns if 'Concentraci贸n Real' in col][0] |
|
|
|
|
|
df_new[col_real_new] = None |
|
for idx in df_new.index: |
|
if idx in df.index: |
|
df_new.at[idx, col_real_new] = df.at[idx, col_real_old] |
|
|
|
return df_new |
|
|
|
|
|
with gr.Blocks(theme=gr.themes.Soft()) as interfaz: |
|
gr.Markdown(""" |
|
# 馃搳 Sistema Avanzado de Calibraci贸n con An谩lisis Estad铆stico |
|
Configure los par谩metros, edite los valores en la tabla y luego presione "Calcular" para obtener el an谩lisis. |
|
""") |
|
|
|
with gr.Tab("馃摑 Datos de Calibraci贸n"): |
|
with gr.Row(): |
|
concentracion_input = gr.Number( |
|
value=2000000, |
|
label="Concentraci贸n Inicial", |
|
precision=0 |
|
) |
|
unidad_input = gr.Textbox( |
|
value="UFC", |
|
label="Unidad de Medida", |
|
placeholder="UFC, OD, etc..." |
|
) |
|
filas_slider = gr.Slider( |
|
minimum=1, |
|
maximum=20, |
|
value=7, |
|
step=1, |
|
label="N煤mero de filas" |
|
) |
|
decimales_slider = gr.Slider( |
|
minimum=0, |
|
maximum=5, |
|
value=0, |
|
step=1, |
|
label="N煤mero de Decimales" |
|
) |
|
|
|
with gr.Row(): |
|
calcular_btn = gr.Button("馃攧 Calcular", variant="primary") |
|
limpiar_btn = gr.Button("馃棏 Limpiar Datos", variant="secondary") |
|
ajustar_decimales_btn = gr.Button("馃洜 Ajustar Decimales", variant="secondary") |
|
|
|
with gr.Row(): |
|
ejemplo_ufc_btn = gr.Button("馃搵 Cargar Ejemplo UFC", variant="secondary") |
|
ejemplo_od_btn = gr.Button("馃搵 Cargar Ejemplo OD", variant="secondary") |
|
sinteticos_btn = gr.Button("馃И Generar Datos Sint茅ticos", variant="secondary") |
|
|
|
tabla_output = gr.DataFrame( |
|
row_count=(1, "dynamic"), |
|
col_count=(5, "fixed"), |
|
wrap=True, |
|
label="Tabla de Datos", |
|
interactive=True, |
|
datatype=["number", "number", "number", "number", "number"], |
|
type="pandas", |
|
) |
|
|
|
with gr.Tab("馃搳 An谩lisis y Reporte"): |
|
estado_output = gr.Textbox(label="Estado", interactive=False) |
|
graficos_output = gr.Plot(label="Gr谩ficos de An谩lisis") |
|
informe_output = gr.Markdown(elem_id="informe_output") |
|
|
|
with gr.Row(): |
|
copiar_btn = gr.Button("馃搵 Copiar Informe", variant="secondary") |
|
exportar_word_btn = gr.Button("馃捑 Exportar Informe Word", variant="primary") |
|
exportar_latex_btn = gr.Button("馃捑 Exportar Informe LaTeX", variant="primary") |
|
|
|
exportar_word_file = gr.File(label="Informe en Word") |
|
exportar_latex_file = gr.File(label="Informe en LaTeX") |
|
|
|
|
|
input_components = [tabla_output] |
|
output_components = [estado_output, graficos_output, informe_output] |
|
|
|
|
|
calcular_btn.click( |
|
fn=actualizar_analisis, |
|
inputs=tabla_output, |
|
outputs=output_components |
|
) |
|
|
|
|
|
limpiar_btn.click( |
|
fn=limpiar_datos, |
|
inputs=[], |
|
outputs=[concentracion_input, unidad_input, filas_slider, tabla_output, estado_output, graficos_output, informe_output] |
|
) |
|
|
|
|
|
ejemplo_ufc_btn.click( |
|
fn=cargar_ejemplo_ufc, |
|
outputs=[concentracion_input, unidad_input, filas_slider, tabla_output] |
|
) |
|
|
|
ejemplo_od_btn.click( |
|
fn=cargar_ejemplo_od, |
|
outputs=[concentracion_input, unidad_input, filas_slider, tabla_output] |
|
) |
|
|
|
|
|
sinteticos_btn.click( |
|
fn=generar_datos_sinteticos_evento, |
|
inputs=tabla_output, |
|
outputs=tabla_output |
|
) |
|
|
|
|
|
ajustar_decimales_btn.click( |
|
fn=ajustar_decimales_evento, |
|
inputs=[tabla_output, decimales_slider], |
|
outputs=tabla_output |
|
) |
|
|
|
|
|
concentracion_input.change( |
|
fn=actualizar_tabla_evento, |
|
inputs=[tabla_output, filas_slider, concentracion_input, unidad_input], |
|
outputs=tabla_output |
|
) |
|
|
|
unidad_input.change( |
|
fn=actualizar_tabla_evento, |
|
inputs=[tabla_output, filas_slider, concentracion_input, unidad_input], |
|
outputs=tabla_output |
|
) |
|
|
|
filas_slider.change( |
|
fn=actualizar_tabla_evento, |
|
inputs=[tabla_output, filas_slider, concentracion_input, unidad_input], |
|
outputs=tabla_output |
|
) |
|
|
|
|
|
|
|
|
|
copiar_btn.click( |
|
None, |
|
[], |
|
[], |
|
js=""" |
|
function() { |
|
const informeElement = document.querySelector('#informe_output'); |
|
const range = document.createRange(); |
|
range.selectNode(informeElement); |
|
window.getSelection().removeAllRanges(); |
|
window.getSelection().addRange(range); |
|
document.execCommand('copy'); |
|
window.getSelection().removeAllRanges(); |
|
alert('Informe copiado al portapapeles'); |
|
} |
|
""" |
|
) |
|
|
|
|
|
exportar_word_btn.click( |
|
fn=exportar_word, |
|
inputs=[tabla_output, informe_output], |
|
outputs=exportar_word_file |
|
) |
|
|
|
exportar_latex_btn.click( |
|
fn=exportar_latex, |
|
inputs=[tabla_output, informe_output], |
|
outputs=exportar_latex_file |
|
) |
|
|
|
|
|
def iniciar_con_ejemplo(): |
|
df = generar_tabla(7, 2000000, "UFC") |
|
valores_reales = [2000000, 1600000, 1200000, 800000, 400000, 200000, 100000] |
|
df[f"Concentraci贸n Real (UFC)"] = valores_reales |
|
estado, fig, informe = actualizar_analisis(df) |
|
return ( |
|
2000000, |
|
"UFC", |
|
7, |
|
df, |
|
estado, |
|
fig, |
|
informe |
|
) |
|
|
|
interfaz.load( |
|
fn=iniciar_con_ejemplo, |
|
outputs=[concentracion_input, unidad_input, filas_slider, tabla_output, estado_output, graficos_output, informe_output] |
|
) |
|
|
|
|
|
if __name__ == "__main__": |
|
interfaz.launch() |
|
|