C2MV commited on
Commit
e7df5cc
·
verified ·
1 Parent(s): b526130

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +234 -22
app.py CHANGED
@@ -155,49 +155,261 @@ def generar_graficos(df_valid):
155
  return fig
156
 
157
  def evaluar_calidad_calibracion(df_valid, r_squared, rmse, cv_percent):
158
- # Función de evaluación (sin cambios)
159
- # ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
 
161
  def generar_informe_completo(df_valid):
162
- # Generar el informe completo (sin cambios)
163
- # ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
  def actualizar_analisis(df):
166
- # Actualizar el análisis (sin cambios)
167
- # ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
  def exportar_informe_word(df_valid, informe_md):
170
- # Exportar informe a Word (sin cambios)
171
- # ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
 
173
  def exportar_informe_latex(df_valid, informe_md):
174
- # Exportar informe a LaTeX (sin cambios)
175
- # ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
  def exportar_word(df, informe_md):
178
- # Función para exportar a Word (sin cambios)
179
- # ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
 
181
  def exportar_latex(df, informe_md):
182
- # Función para exportar a LaTeX (sin cambios)
183
- # ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
 
185
  # Funciones de ejemplo
186
  def cargar_ejemplo_ufc():
187
- # Cargar ejemplo UFC (sin cambios)
188
- # ...
 
 
189
 
190
  def cargar_ejemplo_od():
191
- # Cargar ejemplo OD (sin cambios)
192
- # ...
 
 
193
 
194
  def limpiar_datos():
195
- # Limpiar datos (sin cambios)
196
- # ...
 
 
 
 
 
 
 
 
197
 
198
  def generar_datos_sinteticos_evento(df):
199
- # Generar datos sintéticos (sin cambios)
200
- # ...
 
 
 
 
201
 
202
  def actualizar_tabla_evento(df, n_filas, concentracion, unidad):
203
  # Actualizar tabla sin borrar "Concentración Real"
 
155
  return fig
156
 
157
  def evaluar_calidad_calibracion(df_valid, r_squared, rmse, cv_percent):
158
+ """Evaluar la calidad de la calibración y proporcionar recomendaciones"""
159
+ evaluacion = {
160
+ "calidad": "",
161
+ "recomendaciones": [],
162
+ "estado": "✅" if r_squared >= 0.95 and cv_percent <= 15 else "⚠️"
163
+ }
164
+
165
+ if r_squared >= 0.95:
166
+ evaluacion["calidad"] = "Excelente"
167
+ elif r_squared >= 0.90:
168
+ evaluacion["calidad"] = "Buena"
169
+ elif r_squared >= 0.85:
170
+ evaluacion["calidad"] = "Regular"
171
+ else:
172
+ evaluacion["calidad"] = "Deficiente"
173
+
174
+ if r_squared < 0.95:
175
+ evaluacion["recomendaciones"].append("- Considere repetir algunas mediciones para mejorar la correlación")
176
+
177
+ if cv_percent > 15:
178
+ evaluacion["recomendaciones"].append("- La variabilidad es alta. Revise el procedimiento de dilución")
179
+
180
+ if rmse > 0.1 * df_valid[df_valid.columns[-1]].astype(float).mean():
181
+ evaluacion["recomendaciones"].append("- El error de predicción es significativo. Verifique la técnica de medición")
182
+
183
+ return evaluacion
184
 
185
  def generar_informe_completo(df_valid):
186
+ """Generar un informe completo en formato markdown"""
187
+ col_predicha = [col for col in df_valid.columns if 'Predicha' in col][0]
188
+ col_real = [col for col in df_valid.columns if 'Real' in col][0]
189
+
190
+ # Convertir a numérico
191
+ df_valid[col_predicha] = df_valid[col_predicha].astype(float)
192
+ df_valid[col_real] = df_valid[col_real].astype(float)
193
+
194
+ # Calcular estadísticas
195
+ slope, intercept, r_value, p_value, std_err = stats.linregress(df_valid[col_predicha], df_valid[col_real])
196
+ r_squared = r_value ** 2
197
+ rmse = np.sqrt(((df_valid[col_real] - (intercept + slope * df_valid[col_predicha])) ** 2).mean())
198
+ cv = (df_valid[col_real].std() / df_valid[col_real].mean()) * 100 # CV de los valores reales
199
+
200
+ # Evaluar calidad
201
+ evaluacion = evaluar_calidad_calibracion(df_valid, r_squared, rmse, cv)
202
+
203
+ informe = f"""# Informe de Calibración {evaluacion['estado']}
204
+ Fecha: {datetime.now().strftime('%d/%m/%Y %H:%M')}
205
+
206
+ ## Resumen Estadístico
207
+ - **Ecuación de Regresión**: y = {intercept:.4f} + {slope:.4f}x
208
+ - **Coeficiente de correlación (r)**: {r_value:.4f}
209
+ - **Coeficiente de determinación ($R^2$)**: {r_squared:.4f}
210
+ - **Valor p**: {p_value:.4e}
211
+ - **Error estándar de la pendiente**: {std_err:.4f}
212
+ - **Error cuadrático medio (RMSE)**: {rmse:.4f}
213
+ - **Coeficiente de variación (CV)**: {cv:.2f}%
214
+
215
+ ## Evaluación de Calidad
216
+ - **Calidad de la calibración**: {evaluacion['calidad']}
217
+
218
+ ## Recomendaciones
219
+ {chr(10).join(evaluacion['recomendaciones']) if evaluacion['recomendaciones'] else "No hay recomendaciones específicas. La calibración cumple con los criterios de calidad."}
220
+
221
+ ## Decisión
222
+ {("✅ APROBADO - La calibración cumple con los criterios de calidad establecidos" if evaluacion['estado'] == "✅" else "⚠️ REQUIERE REVISIÓN - La calibración necesita ajustes según las recomendaciones anteriores")}
223
+
224
+ ---
225
+ *Nota: Este informe fue generado automáticamente. Por favor, revise los resultados y valide según sus criterios específicos.*
226
+ """
227
+ return informe, evaluacion['estado']
228
 
229
  def actualizar_analisis(df):
230
+ if df is None or df.empty:
231
+ return "Error en los datos", None, "No se pueden generar análisis"
232
+
233
+ col_predicha = [col for col in df.columns if 'Predicha' in col][0]
234
+ col_real = [col for col in df.columns if 'Real' in col][0]
235
+
236
+ # Convertir columnas a numérico
237
+ df[col_predicha] = pd.to_numeric(df[col_predicha], errors='coerce')
238
+ df[col_real] = pd.to_numeric(df[col_real], errors='coerce')
239
+
240
+ df_valid = df.dropna(subset=[col_predicha, col_real])
241
+
242
+ if len(df_valid) < 2:
243
+ return "Se necesitan más datos", None, "Se requieren al menos dos valores reales para el análisis"
244
+
245
+ # Calcular la regresión y agregar 'Ajuste Lineal'
246
+ slope, intercept, r_value, p_value, std_err = stats.linregress(df_valid[col_predicha], df_valid[col_real])
247
+ df_valid['Ajuste Lineal'] = intercept + slope * df_valid[col_predicha]
248
+
249
+ fig = generar_graficos(df_valid)
250
+ informe, estado = generar_informe_completo(df_valid)
251
+
252
+ return estado, fig, informe
253
 
254
  def exportar_informe_word(df_valid, informe_md):
255
+ # Crear documento Word
256
+ doc = docx.Document()
257
+
258
+ # Estilos APA 7
259
+ style = doc.styles['Normal']
260
+ font = style.font
261
+ font.name = 'Times New Roman'
262
+ font.size = Pt(12)
263
+
264
+ # Título centrado
265
+ titulo = doc.add_heading('Informe de Calibración', 0)
266
+ titulo.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
267
+
268
+ # Fecha
269
+ fecha = doc.add_paragraph(f"Fecha: {datetime.now().strftime('%d/%m/%Y %H:%M')}")
270
+ fecha.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
271
+
272
+ # Insertar gráfico
273
+ if os.path.exists('grafico.png'):
274
+ doc.add_picture('grafico.png', width=Inches(6))
275
+ ultimo_parrafo = doc.paragraphs[-1]
276
+ ultimo_parrafo.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
277
+
278
+ # Leyenda del gráfico en estilo APA 7
279
+ leyenda = doc.add_paragraph('Figura 1. Gráfico de calibración.')
280
+ leyenda_format = leyenda.paragraph_format
281
+ leyenda_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
282
+ leyenda.style = doc.styles['Caption']
283
+
284
+ # Agregar contenido del informe
285
+ doc.add_heading('Resumen Estadístico', level=1)
286
+ for linea in informe_md.split('\n'):
287
+ if linea.startswith('##'):
288
+ doc.add_heading(linea.replace('##', '').strip(), level=2)
289
+ else:
290
+ doc.add_paragraph(linea)
291
+
292
+ # Añadir tabla de datos
293
+ doc.add_heading('Tabla de Datos de Calibración', level=1)
294
+
295
+ # Convertir DataFrame a lista de listas
296
+ tabla_datos = df_valid.reset_index(drop=True)
297
+ tabla_datos = tabla_datos.round(4) # Redondear a 4 decimales si es necesario
298
+ columnas = tabla_datos.columns.tolist()
299
+ registros = tabla_datos.values.tolist()
300
+
301
+ # Crear tabla en Word
302
+ tabla = doc.add_table(rows=1 + len(registros), cols=len(columnas))
303
+ tabla.style = 'Table Grid'
304
+
305
+ # Añadir los encabezados
306
+ hdr_cells = tabla.rows[0].cells
307
+ for idx, col_name in enumerate(columnas):
308
+ hdr_cells[idx].text = col_name
309
+
310
+ # Añadir los registros
311
+ for i, registro in enumerate(registros):
312
+ row_cells = tabla.rows[i + 1].cells
313
+ for j, valor in enumerate(registro):
314
+ row_cells[j].text = str(valor)
315
+
316
+ # Formatear fuente de la tabla
317
+ for row in tabla.rows:
318
+ for cell in row.cells:
319
+ for paragraph in cell.paragraphs:
320
+ paragraph.style = doc.styles['Normal']
321
+
322
+ # Guardar documento
323
+ filename = 'informe_calibracion.docx'
324
+ doc.save(filename)
325
+ return filename
326
 
327
  def exportar_informe_latex(df_valid, informe_md):
328
+ # Generar código LaTeX
329
+ informe_tex = r"""\documentclass{article}
330
+ \usepackage[spanish]{babel}
331
+ \usepackage{amsmath}
332
+ \usepackage{graphicx}
333
+ \usepackage{booktabs}
334
+ \begin{document}
335
+ """
336
+ informe_tex += informe_md.replace('#', '').replace('**', '\\textbf{').replace('*', '\\textit{')
337
+ informe_tex += r"""
338
+ \end{document}
339
+ """
340
+ filename = 'informe_calibracion.tex'
341
+ with open(filename, 'w') as f:
342
+ f.write(informe_tex)
343
+ return filename
344
 
345
  def exportar_word(df, informe_md):
346
+ df_valid = df.copy()
347
+ col_predicha = [col for col in df_valid.columns if 'Predicha' in col][0]
348
+ col_real = [col for col in df_valid.columns if 'Real' in col][0]
349
+
350
+ # Convertir columnas a numérico
351
+ df_valid[col_predicha] = pd.to_numeric(df_valid[col_predicha], errors='coerce')
352
+ df_valid[col_real] = pd.to_numeric(df_valid[col_real], errors='coerce')
353
+
354
+ df_valid = df_valid.dropna(subset=[col_predicha, col_real])
355
+
356
+ if df_valid.empty:
357
+ return None
358
+
359
+ filename = exportar_informe_word(df_valid, informe_md)
360
+
361
+ return filename # Retornamos el nombre del archivo
362
 
363
  def exportar_latex(df, informe_md):
364
+ df_valid = df.copy()
365
+ col_predicha = [col for col in df_valid.columns if 'Predicha' in col][0]
366
+ col_real = [col for col in df_valid.columns if 'Real' in col][0]
367
+
368
+ # Convertir columnas a numérico
369
+ df_valid[col_predicha] = pd.to_numeric(df_valid[col_predicha], errors='coerce')
370
+ df_valid[col_real] = pd.to_numeric(df_valid[col_real], errors='coerce')
371
+
372
+ df_valid = df_valid.dropna(subset=[col_predicha, col_real])
373
+
374
+ if df_valid.empty:
375
+ return None
376
+
377
+ filename = exportar_informe_latex(df_valid, informe_md)
378
+
379
+ return filename # Retornamos el nombre del archivo
380
 
381
  # Funciones de ejemplo
382
  def cargar_ejemplo_ufc():
383
+ df = generar_tabla(7, 2000000, "UFC")
384
+ valores_reales = [2000000, 1600000, 1200000, 800000, 400000, 200000, 100000]
385
+ df[f"Concentración Real (UFC)"] = valores_reales
386
+ return 2000000, "UFC", 7, df
387
 
388
  def cargar_ejemplo_od():
389
+ df = generar_tabla(7, 1.0, "OD")
390
+ valores_reales = [1.000, 0.800, 0.600, 0.400, 0.200, 0.100, 0.050]
391
+ df[f"Concentración Real (OD)"] = valores_reales
392
+ return 1.0, "OD", 7, df
393
 
394
  def limpiar_datos():
395
+ df = generar_tabla(7, 2000000, "UFC")
396
+ return (
397
+ 2000000, # Concentración Inicial
398
+ "UFC", # Unidad de Medida
399
+ 7, # Número de filas
400
+ df, # Tabla Output
401
+ "", # Estado Output
402
+ None, # Gráficos Output
403
+ "" # Informe Output
404
+ )
405
 
406
  def generar_datos_sinteticos_evento(df):
407
+ df = df.copy()
408
+ col_predicha = [col for col in df.columns if 'Predicha' in col][0]
409
+ df[col_predicha] = pd.to_numeric(df[col_predicha], errors='coerce')
410
+ desviacion_std = 0.05 * df[col_predicha].mean() # 5% de la media como desviación estándar
411
+ df = generar_datos_sinteticos(df, desviacion_std)
412
+ return df
413
 
414
  def actualizar_tabla_evento(df, n_filas, concentracion, unidad):
415
  # Actualizar tabla sin borrar "Concentración Real"