Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
@@ -1,145 +1,142 @@
|
|
1 |
import gradio as gr
|
2 |
import pandas as pd
|
3 |
import numpy as np
|
4 |
-
import matplotlib.pyplot as plt
|
5 |
-
import seaborn as sns
|
6 |
import geopandas as gpd
|
|
|
|
|
7 |
from scipy.stats import chi2_contingency
|
8 |
-
|
|
|
|
|
|
|
9 |
import folium
|
10 |
from folium.plugins import HeatMap
|
11 |
|
12 |
-
#
|
13 |
-
# 1. CARGA
|
14 |
-
#
|
15 |
-
|
16 |
-
|
17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
categorias = {
|
19 |
-
'genero_cat':
|
20 |
-
'regimen_cat':
|
21 |
-
'estrato_cat':
|
22 |
}
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
#
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
plt.title(f"Distribución de {col}")
|
53 |
-
plt.xticks(rotation=30)
|
54 |
-
plt.tight_layout()
|
55 |
-
path = f"uni_{col}.png"
|
56 |
-
plt.savefig(path)
|
57 |
-
rutas.append(path)
|
58 |
-
plt.close()
|
59 |
-
return rutas
|
60 |
-
|
61 |
-
def generar_bivariado():
|
62 |
-
relaciones_bi = [
|
63 |
-
('anca_cat', 'biopsia_positiva'), ('anca_cat', 'mpo_cat'),
|
64 |
-
('anca_cat', 'pr3_cat'), ('estrato_cat', 'biopsia_positiva'),
|
65 |
-
('genero_cat', 'anca_cat'), ('regimen_cat', 'anca_cat'),
|
66 |
-
('sindrome', 'biopsia_positiva')
|
67 |
-
]
|
68 |
-
rutas = []
|
69 |
-
for x, y in relaciones_bi:
|
70 |
-
plt.figure(figsize=(6, 4))
|
71 |
-
sns.countplot(data=df, x=x, hue=y)
|
72 |
-
plt.title(f"{x} vs {y}")
|
73 |
-
plt.xticks(rotation=30)
|
74 |
-
plt.tight_layout()
|
75 |
-
path = f"bi_{x}_{y}.png"
|
76 |
-
plt.savefig(path)
|
77 |
-
rutas.append(path)
|
78 |
-
plt.close()
|
79 |
-
return rutas
|
80 |
-
|
81 |
-
def generar_chi2():
|
82 |
-
relaciones_bi = [
|
83 |
-
('anca_cat', 'biopsia_positiva'), ('anca_cat', 'mpo_cat'),
|
84 |
-
('anca_cat', 'pr3_cat'), ('estrato_cat', 'biopsia_positiva'),
|
85 |
-
('genero_cat', 'anca_cat'), ('regimen_cat', 'anca_cat'),
|
86 |
-
('sindrome', 'biopsia_positiva')
|
87 |
-
]
|
88 |
-
resultados = []
|
89 |
-
for var1, var2 in relaciones_bi:
|
90 |
-
tabla = pd.crosstab(df[var1], df[var2])
|
91 |
-
chi, p, dof, _ = chi2_contingency(tabla)
|
92 |
-
resultados.append((f"{var1} vs {var2}", tabla, chi, p, dof))
|
93 |
-
return resultados
|
94 |
-
|
95 |
-
def generar_mapa_coropletico():
|
96 |
-
gdf = gpd.read_file("https://datosabiertos.bogota.gov.co/dataset/856cb657-8ca3-4ee8-857f-37211173b1f8/resource/497b8756-0927-4aee-8da9-ca4e32ca3a8a/download/loca.json")
|
97 |
-
df_loc = df.copy()
|
98 |
-
df_loc['localidad'] = df_loc['localidad'].astype(str)
|
99 |
-
counts = df_loc['localidad'].value_counts().reset_index()
|
100 |
-
counts.columns = ['localidad', 'casos']
|
101 |
-
gdf['localidad'] = gdf['NOMBRE'].str.upper()
|
102 |
-
merged = gdf.merge(counts, how='left', left_on='localidad', right_on='localidad').fillna(0)
|
103 |
-
m = merged.explore(column='casos', cmap='OrRd', legend=True)
|
104 |
-
m.save("coropletico.html")
|
105 |
-
with open("coropletico.html", "r", encoding="utf-8") as f:
|
106 |
-
return f.read()
|
107 |
-
|
108 |
-
def generar_mapa_kernel():
|
109 |
-
if 'latitud' in df.columns and 'longitud' in df.columns:
|
110 |
-
puntos = df[['latitud', 'longitud']].dropna()
|
111 |
-
m = folium.Map(location=[4.65, -74.1], zoom_start=11)
|
112 |
-
HeatMap(puntos.values.tolist(), radius=12).add_to(m)
|
113 |
-
m.save("heatmap.html")
|
114 |
-
with open("heatmap.html", "r", encoding="utf-8") as f:
|
115 |
-
return f.read()
|
116 |
-
else:
|
117 |
-
return "No hay coordenadas geográficas disponibles."
|
118 |
-
|
119 |
-
# ===========================
|
120 |
-
# 3. INTERFAZ AUTOMÁTICA PROFESIONAL
|
121 |
-
# ===========================
|
122 |
with gr.Blocks() as demo:
|
123 |
-
gr.Markdown("# Tablero
|
124 |
-
|
125 |
-
with gr.
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
|
145 |
demo.launch()
|
|
|
1 |
import gradio as gr
|
2 |
import pandas as pd
|
3 |
import numpy as np
|
|
|
|
|
4 |
import geopandas as gpd
|
5 |
+
import plotly.express as px
|
6 |
+
import plotly.graph_objects as go
|
7 |
from scipy.stats import chi2_contingency
|
8 |
+
import matplotlib.pyplot as plt
|
9 |
+
import seaborn as sns
|
10 |
+
import io
|
11 |
+
import base64
|
12 |
import folium
|
13 |
from folium.plugins import HeatMap
|
14 |
|
15 |
+
# =========================
|
16 |
+
# 1. CARGA DE DATOS
|
17 |
+
# =========================
|
18 |
+
data = pd.read_csv("VasculitisAsociadasA-BDD10jul24_DATA_2025-03-19_1033.csv")
|
19 |
+
geo_localidades = gpd.read_file("loca.json")
|
20 |
+
calidad_aire = gpd.read_file("pm25_prom_anual_2023.geojson")
|
21 |
+
ozono = gpd.read_file("ozono_prom_anual_2022.geojson")
|
22 |
+
temperatura = gpd.read_file("temp_anualprom_2023.geojson")
|
23 |
+
precipitacion = gpd.read_file("precip_anualacum_2023.geojson")
|
24 |
+
viento = gpd.read_file("vel_viento_0_23h_anual_2023.geojson")
|
25 |
+
estaciones = gpd.read_file("estacion_calidad_aire.geojson")
|
26 |
+
|
27 |
+
# =========================
|
28 |
+
# 2. PROCESAMIENTO
|
29 |
+
# =========================
|
30 |
categorias = {
|
31 |
+
'genero_cat': data['genero'].map({0: 'Masculino', 1: 'Femenino'}),
|
32 |
+
'regimen_cat': data['regimen'].map({1: 'Contributivo', 2: 'Subsidiado'}),
|
33 |
+
'estrato_cat': data['estrato'].map({0: 'Bajo', 1: 'Bajo', 2: 'Bajo', 3: 'Medio', 4: 'Medio', 5: 'Alto', 6: 'Alto'})
|
34 |
}
|
35 |
+
data = data.assign(**categorias)
|
36 |
+
|
37 |
+
data['anca_cat'] = data['ancas'].map({0: 'Negativo', 1: 'Positivo'}).fillna('No definido')
|
38 |
+
data['mpo_cat'] = data['mpo'].map({0: 'Negativo', 1: 'Positivo'}).fillna('No definido')
|
39 |
+
data['pr3_cat'] = data['pr3'].map({0: 'Negativo', 1: 'Positivo'}).fillna('No definido')
|
40 |
+
|
41 |
+
tipo_biopsia = [col for col in data.columns if col.startswith('biopsia___')]
|
42 |
+
data['biopsia_positiva'] = data[tipo_biopsia].sum(axis=1).apply(lambda x: 'Sí' if x > 0 else 'No')
|
43 |
+
data['anca_y_renal'] = np.where((data['ancas'] == 1) & (data['biopsia_positiva'] == 'Sí'), 'Sí', 'No')
|
44 |
+
|
45 |
+
# =========================
|
46 |
+
# 3. FUNCIONES DE FILTRADO
|
47 |
+
# =========================
|
48 |
+
def aplicar_filtros(df, genero, edad, localidad, anca_tipo, antecedentes):
|
49 |
+
if genero != "Todos":
|
50 |
+
df = df[df['genero_cat'] == genero]
|
51 |
+
df = df[(df['edad'] >= edad[0]) & (df['edad'] <= edad[1])]
|
52 |
+
if localidad:
|
53 |
+
df = df[df['localidad'].isin(localidad)]
|
54 |
+
if anca_tipo != "Todos":
|
55 |
+
df = df[df['anca_cat'] == anca_tipo]
|
56 |
+
for ant in antecedentes:
|
57 |
+
if ant in df.columns:
|
58 |
+
df = df[df[ant] == 1]
|
59 |
+
return df
|
60 |
+
|
61 |
+
# =========================
|
62 |
+
# 4. NUEVOS COMPONENTES UI
|
63 |
+
# =========================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
with gr.Blocks() as demo:
|
65 |
+
gr.Markdown("# Tablero de Análisis de Vasculitis ANCA en Bogotá")
|
66 |
+
|
67 |
+
with gr.Accordion("Filtros de Subgrupo", open=False):
|
68 |
+
genero = gr.Radio(["Todos", "Masculino", "Femenino"], label="Género")
|
69 |
+
edad = gr.Slider(0, 100, step=1, value=(0, 100), label="Edad")
|
70 |
+
localidades_opciones = sorted(data['localidad'].dropna().unique().tolist())
|
71 |
+
localidad = gr.Dropdown(localidades_opciones, label="Localidad", multiselect=True)
|
72 |
+
anca = gr.Radio(["Todos", "Positivo", "Negativo"], label="ANCA")
|
73 |
+
antecedentes = gr.CheckboxGroup(choices=['diabetes', 'falla_cardiaca', 'epoc', 'hta'], label="Antecedentes Clínicos")
|
74 |
+
btn_aplicar = gr.Button("Aplicar Filtros")
|
75 |
+
|
76 |
+
resultados_univariados = gr.Gallery(label="Distribuciones Univariadas")
|
77 |
+
resultados_bivariados = gr.Gallery(label="Relaciones Bivariadas")
|
78 |
+
resultados_chi = gr.DataFrame()
|
79 |
+
html_mapa = gr.HTML()
|
80 |
+
mapa_plot = gr.Plot()
|
81 |
+
|
82 |
+
def actualizar_tablero(genero, edad, localidad, anca, antecedentes):
|
83 |
+
df_filtrado = aplicar_filtros(data, genero, edad, localidad, anca, antecedentes)
|
84 |
+
if df_filtrado.empty:
|
85 |
+
return [[], [], pd.DataFrame(), "<h4>No hay datos para los filtros seleccionados</h4>", go.Figure()]
|
86 |
+
|
87 |
+
imgs_uni = []
|
88 |
+
for col in ['edad', 'genero_cat', 'regimen_cat', 'estrato_cat', 'anca_cat', 'mpo_cat', 'pr3_cat', 'biopsia_positiva', 'anca_y_renal']:
|
89 |
+
plt.figure(figsize=(5, 4))
|
90 |
+
if df_filtrado[col].dtype == 'object':
|
91 |
+
sns.countplot(data=df_filtrado, x=col, order=df_filtrado[col].value_counts().index)
|
92 |
+
else:
|
93 |
+
sns.histplot(df_filtrado[col], kde=True)
|
94 |
+
plt.xticks(rotation=30)
|
95 |
+
plt.tight_layout()
|
96 |
+
path = f"plot_uni_{col}.png"
|
97 |
+
plt.savefig(path)
|
98 |
+
imgs_uni.append(path)
|
99 |
+
plt.close()
|
100 |
+
|
101 |
+
imgs_bi = []
|
102 |
+
for x, y in [('anca_cat', 'biopsia_positiva'), ('estrato_cat', 'anca_cat')]:
|
103 |
+
plt.figure(figsize=(6, 4))
|
104 |
+
sns.countplot(data=df_filtrado, x=x, hue=y)
|
105 |
+
plt.tight_layout()
|
106 |
+
path = f"plot_bi_{x}_{y}.png"
|
107 |
+
plt.savefig(path)
|
108 |
+
imgs_bi.append(path)
|
109 |
+
plt.close()
|
110 |
+
|
111 |
+
tabla = pd.crosstab(df_filtrado['genero_cat'], df_filtrado['anca_cat'])
|
112 |
+
chi2, p, dof, _ = chi2_contingency(tabla)
|
113 |
+
|
114 |
+
resumen = df_filtrado.groupby("localidad")['ancas'].count().reset_index(name='casos')
|
115 |
+
geo_localidades['localidad'] = geo_localidades['NOMBRE'].str.upper()
|
116 |
+
merged = geo_localidades.merge(resumen, left_on='localidad', right_on='localidad', how='left').fillna(0)
|
117 |
+
m = folium.Map(location=[4.65, -74.1], zoom_start=11)
|
118 |
+
folium.Choropleth(
|
119 |
+
geo_data=merged,
|
120 |
+
data=merged,
|
121 |
+
columns=['localidad', 'casos'],
|
122 |
+
key_on='feature.properties.localidad',
|
123 |
+
fill_color='YlOrRd',
|
124 |
+
fill_opacity=0.7,
|
125 |
+
line_opacity=0.2,
|
126 |
+
legend_name='Casos de Vasculitis'
|
127 |
+
).add_to(m)
|
128 |
+
path_map = "folium_map.html"
|
129 |
+
m.save(path_map)
|
130 |
+
with open(path_map, 'r', encoding='utf-8') as f:
|
131 |
+
html_out = f.read()
|
132 |
+
|
133 |
+
fig = px.density_mapbox(df_filtrado.dropna(subset=['latitud', 'longitud']), lat='latitud', lon='longitud',
|
134 |
+
z=[1]*len(df_filtrado), radius=10,
|
135 |
+
center=dict(lat=4.65, lon=-74.1), zoom=10, mapbox_style="carto-positron")
|
136 |
+
|
137 |
+
return [imgs_uni, imgs_bi, tabla.reset_index(), html_out, fig]
|
138 |
+
|
139 |
+
btn_aplicar.click(actualizar_tablero, inputs=[genero, edad, localidad, anca, antecedentes],
|
140 |
+
outputs=[resultados_univariados, resultados_bivariados, resultados_chi, html_mapa, mapa_plot])
|
141 |
|
142 |
demo.launch()
|