Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
|
|
| 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 matplotlib.pyplot as plt
|
| 7 |
import seaborn as sns
|
| 8 |
import folium
|
|
@@ -19,6 +19,7 @@ data = data.dropna(subset=['latitud', 'longitud'])
|
|
| 19 |
data['geometry'] = data.apply(lambda row: Point(row['longitud'], row['latitud']), axis=1)
|
| 20 |
data = gpd.GeoDataFrame(data, geometry='geometry', crs='EPSG:4326')
|
| 21 |
|
|
|
|
| 22 |
geo_localidades = gpd.read_file("loca.json")
|
| 23 |
geo_localidades.columns = geo_localidades.columns.str.lower()
|
| 24 |
geo_localidades = geo_localidades.rename(columns={"locnombre": "localidad"})
|
|
@@ -71,96 +72,135 @@ def aplicar_filtros(df, genero, edad_rango, localidades, compromiso_renal, antec
|
|
| 71 |
df_filtrado = df_filtrado[df_filtrado[ant] == 1]
|
| 72 |
return df_filtrado
|
| 73 |
|
| 74 |
-
#
|
| 75 |
-
def
|
| 76 |
-
|
| 77 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
return None
|
| 79 |
plt.figure(figsize=(6, 4))
|
| 80 |
-
if
|
| 81 |
-
sns.countplot(data=
|
| 82 |
else:
|
| 83 |
-
sns.histplot(
|
| 84 |
-
plt.title(f"Distribución de {
|
| 85 |
-
path = f"uni_{
|
| 86 |
plt.tight_layout()
|
| 87 |
plt.savefig(path)
|
| 88 |
plt.close()
|
| 89 |
return path
|
| 90 |
|
| 91 |
-
#
|
| 92 |
-
def
|
| 93 |
-
|
| 94 |
-
if
|
| 95 |
return None
|
| 96 |
plt.figure(figsize=(6, 4))
|
| 97 |
-
if
|
| 98 |
-
sns.countplot(data=
|
| 99 |
else:
|
| 100 |
-
sns.scatterplot(data=
|
| 101 |
-
plt.title(f"{
|
| 102 |
-
path = f"bi_{
|
| 103 |
plt.tight_layout()
|
| 104 |
plt.savefig(path)
|
| 105 |
plt.close()
|
| 106 |
return path
|
| 107 |
|
| 108 |
-
# Interfaz
|
| 109 |
def lanzar_app():
|
| 110 |
with gr.Blocks() as demo:
|
| 111 |
-
gr.Markdown("## Tablero Interactivo: Vasculitis ANCA")
|
| 112 |
|
| 113 |
with gr.Row():
|
| 114 |
genero = gr.Dropdown(label="Género", choices=["Todos", "Masculino", "Femenino"], value="Todos")
|
| 115 |
edad = gr.Slider(label="Edad", minimum=0, maximum=100, value=(20, 80))
|
| 116 |
with gr.Row():
|
| 117 |
localidades = gr.Dropdown(label="Localidades", choices=sorted(data['localidad'].dropna().unique()), multiselect=True)
|
| 118 |
-
|
| 119 |
antecedentes = gr.CheckboxGroup(label="Antecedentes", choices=["diabetes", "hta", "epoc", "falla_cardiaca"])
|
| 120 |
|
| 121 |
with gr.Tab("Mapa Coroplético"):
|
| 122 |
capas = gr.CheckboxGroup(label="Capas Ambientales", choices=list(capas_ambientales.keys()))
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
df_f = aplicar_filtros(data, genero, edad, localidades, compromiso_renal, antecedentes)
|
| 128 |
-
return generar_mapa_coropletico(df_f, capas)
|
| 129 |
-
|
| 130 |
-
btn_coro.click(mostrar_mapa, inputs=[genero, edad, localidades, compromiso_renal, antecedentes, capas], outputs=mapa_html)
|
| 131 |
|
| 132 |
with gr.Tab("Mapa de Calor"):
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
df_f = aplicar_filtros(data, genero, edad, localidades, compromiso_renal, antecedentes)
|
| 138 |
-
return generar_mapa_calor(df_f)
|
| 139 |
-
|
| 140 |
-
btn_heat.click(mostrar_heat, inputs=[genero, edad, localidades, compromiso_renal, antecedentes], outputs=mapa_heat)
|
| 141 |
|
| 142 |
with gr.Tab("Univariado"):
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
|
| 148 |
with gr.Tab("Bivariado"):
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
|
| 155 |
with gr.Tab("Ayuda"):
|
| 156 |
gr.Markdown("""
|
| 157 |
-
**
|
| 158 |
-
-
|
| 159 |
-
-
|
| 160 |
-
-
|
| 161 |
-
-
|
| 162 |
-
- Gráficos univariados: muestra distribución de una variable.
|
| 163 |
-
- Gráficos bivariados: relación entre dos variables relevantes.
|
| 164 |
""")
|
| 165 |
|
| 166 |
demo.launch()
|
|
|
|
| 1 |
+
# app.py
|
| 2 |
import gradio as gr
|
| 3 |
import pandas as pd
|
| 4 |
import numpy as np
|
| 5 |
import geopandas as gpd
|
|
|
|
| 6 |
import matplotlib.pyplot as plt
|
| 7 |
import seaborn as sns
|
| 8 |
import folium
|
|
|
|
| 19 |
data['geometry'] = data.apply(lambda row: Point(row['longitud'], row['latitud']), axis=1)
|
| 20 |
data = gpd.GeoDataFrame(data, geometry='geometry', crs='EPSG:4326')
|
| 21 |
|
| 22 |
+
# Localidades
|
| 23 |
geo_localidades = gpd.read_file("loca.json")
|
| 24 |
geo_localidades.columns = geo_localidades.columns.str.lower()
|
| 25 |
geo_localidades = geo_localidades.rename(columns={"locnombre": "localidad"})
|
|
|
|
| 72 |
df_filtrado = df_filtrado[df_filtrado[ant] == 1]
|
| 73 |
return df_filtrado
|
| 74 |
|
| 75 |
+
# Mapa coroplético
|
| 76 |
+
def generar_mapa_coropletico(df, capas):
|
| 77 |
+
df_grouped = df.groupby('localidad').size().reset_index(name='casos')
|
| 78 |
+
geo_local_copy = geo_localidades.merge(df_grouped, on='localidad', how='left').fillna({'casos': 0})
|
| 79 |
+
m = folium.Map(location=[4.65, -74.1], zoom_start=11)
|
| 80 |
+
folium.Choropleth(
|
| 81 |
+
geo_data=geo_local_copy,
|
| 82 |
+
name='Casos por localidad',
|
| 83 |
+
data=geo_local_copy,
|
| 84 |
+
columns=['localidad', 'casos'],
|
| 85 |
+
key_on='feature.properties.localidad',
|
| 86 |
+
fill_color='YlOrRd',
|
| 87 |
+
fill_opacity=0.7,
|
| 88 |
+
line_opacity=0.3,
|
| 89 |
+
legend_name='Número de casos'
|
| 90 |
+
).add_to(m)
|
| 91 |
+
|
| 92 |
+
for _, row in geo_local_copy.iterrows():
|
| 93 |
+
folium.Marker(
|
| 94 |
+
location=row['geometry'].centroid.coords[0][::-1],
|
| 95 |
+
popup=f"{row['localidad']}: {int(row['casos'])} casos",
|
| 96 |
+
icon=folium.Icon(color='blue', icon='info-sign')
|
| 97 |
+
).add_to(m)
|
| 98 |
+
|
| 99 |
+
for _, row in df.iterrows():
|
| 100 |
+
folium.CircleMarker(
|
| 101 |
+
location=(row['latitud'], row['longitud']),
|
| 102 |
+
radius=4,
|
| 103 |
+
popup=f"Edad: {row['edad']}, Género: {row['genero_cat']}, Estrato: {row['estrato_cat']}, Creatinina: {row.get('creatinina', '')}",
|
| 104 |
+
color='black', fill=True, fill_opacity=0.6
|
| 105 |
+
).add_to(m)
|
| 106 |
+
|
| 107 |
+
for capa in capas:
|
| 108 |
+
if capa in capas_ambientales:
|
| 109 |
+
gdf = capas_ambientales[capa]
|
| 110 |
+
folium.GeoJson(gdf, name=capa, tooltip=folium.GeoJsonTooltip(fields=gdf.columns[:2].tolist())).add_to(m)
|
| 111 |
+
|
| 112 |
+
folium.LayerControl().add_to(m)
|
| 113 |
+
return m._repr_html_()
|
| 114 |
+
|
| 115 |
+
# Mapa calor
|
| 116 |
+
def generar_mapa_calor(df):
|
| 117 |
+
m = folium.Map(location=[4.65, -74.1], zoom_start=11)
|
| 118 |
+
if df.empty:
|
| 119 |
+
return m._repr_html_()
|
| 120 |
+
heat_data = df[['latitud', 'longitud']].dropna().values.tolist()
|
| 121 |
+
HeatMap(heat_data, radius=14).add_to(m)
|
| 122 |
+
return m._repr_html_()
|
| 123 |
+
|
| 124 |
+
# Gráfico univariado
|
| 125 |
+
def grafico_univariado(var, genero, edad, localidades, compromiso_renal, antecedentes):
|
| 126 |
+
df = aplicar_filtros(data, genero, edad, localidades, compromiso_renal, antecedentes)
|
| 127 |
+
if df.empty:
|
| 128 |
return None
|
| 129 |
plt.figure(figsize=(6, 4))
|
| 130 |
+
if df[var].dtype == 'object':
|
| 131 |
+
sns.countplot(data=df, x=var)
|
| 132 |
else:
|
| 133 |
+
sns.histplot(df[var], kde=True)
|
| 134 |
+
plt.title(f"Distribución de {var}")
|
| 135 |
+
path = f"uni_{var}.png"
|
| 136 |
plt.tight_layout()
|
| 137 |
plt.savefig(path)
|
| 138 |
plt.close()
|
| 139 |
return path
|
| 140 |
|
| 141 |
+
# Gráfico bivariado
|
| 142 |
+
def grafico_bivariado(x, y, genero, edad, localidades, compromiso_renal, antecedentes):
|
| 143 |
+
df = aplicar_filtros(data, genero, edad, localidades, compromiso_renal, antecedentes)
|
| 144 |
+
if df.empty:
|
| 145 |
return None
|
| 146 |
plt.figure(figsize=(6, 4))
|
| 147 |
+
if df[x].dtype == 'object' or df[y].dtype == 'object':
|
| 148 |
+
sns.countplot(data=df, x=x, hue=y)
|
| 149 |
else:
|
| 150 |
+
sns.scatterplot(data=df, x=x, y=y)
|
| 151 |
+
plt.title(f"{x} vs {y}")
|
| 152 |
+
path = f"bi_{x}_{y}.png"
|
| 153 |
plt.tight_layout()
|
| 154 |
plt.savefig(path)
|
| 155 |
plt.close()
|
| 156 |
return path
|
| 157 |
|
| 158 |
+
# Interfaz
|
| 159 |
def lanzar_app():
|
| 160 |
with gr.Blocks() as demo:
|
| 161 |
+
gr.Markdown("## 🧬 Tablero Geoespacial Interactivo: Vasculitis ANCA con Compromiso Renal")
|
| 162 |
|
| 163 |
with gr.Row():
|
| 164 |
genero = gr.Dropdown(label="Género", choices=["Todos", "Masculino", "Femenino"], value="Todos")
|
| 165 |
edad = gr.Slider(label="Edad", minimum=0, maximum=100, value=(20, 80))
|
| 166 |
with gr.Row():
|
| 167 |
localidades = gr.Dropdown(label="Localidades", choices=sorted(data['localidad'].dropna().unique()), multiselect=True)
|
| 168 |
+
compromiso = gr.Dropdown(label="Compromiso Renal", choices=["Todos", "Sí", "No"], value="Todos")
|
| 169 |
antecedentes = gr.CheckboxGroup(label="Antecedentes", choices=["diabetes", "hta", "epoc", "falla_cardiaca"])
|
| 170 |
|
| 171 |
with gr.Tab("Mapa Coroplético"):
|
| 172 |
capas = gr.CheckboxGroup(label="Capas Ambientales", choices=list(capas_ambientales.keys()))
|
| 173 |
+
btn = gr.Button("Mostrar")
|
| 174 |
+
mapa = gr.HTML()
|
| 175 |
+
btn.click(fn=lambda g, e, l, c, a, cap: generar_mapa_coropletico(aplicar_filtros(data, g, e, l, c, a), cap),
|
| 176 |
+
inputs=[genero, edad, localidades, compromiso, antecedentes, capas], outputs=mapa)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 177 |
|
| 178 |
with gr.Tab("Mapa de Calor"):
|
| 179 |
+
btn2 = gr.Button("Mostrar")
|
| 180 |
+
salida = gr.HTML()
|
| 181 |
+
btn2.click(fn=lambda g, e, l, c, a: generar_mapa_calor(aplicar_filtros(data, g, e, l, c, a)),
|
| 182 |
+
inputs=[genero, edad, localidades, compromiso, antecedentes], outputs=salida)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 183 |
|
| 184 |
with gr.Tab("Univariado"):
|
| 185 |
+
var = gr.Dropdown(label="Variable", choices=['edad', 'genero_cat', 'estrato_cat', 'anca_y_renal', 'sindrome'])
|
| 186 |
+
btn3 = gr.Button("Graficar")
|
| 187 |
+
img = gr.Image()
|
| 188 |
+
btn3.click(grafico_univariado, inputs=[var, genero, edad, localidades, compromiso, antecedentes], outputs=img)
|
| 189 |
|
| 190 |
with gr.Tab("Bivariado"):
|
| 191 |
+
x = gr.Dropdown(label="X", choices=['genero_cat', 'estrato_cat', 'edad', 'mpo_cat'])
|
| 192 |
+
y = gr.Dropdown(label="Y", choices=['anca_y_renal', 'biopsia_positiva', 'creatinina'])
|
| 193 |
+
btn4 = gr.Button("Graficar")
|
| 194 |
+
img2 = gr.Image()
|
| 195 |
+
btn4.click(grafico_bivariado, inputs=[x, y, genero, edad, localidades, compromiso, antecedentes], outputs=img2)
|
| 196 |
|
| 197 |
with gr.Tab("Ayuda"):
|
| 198 |
gr.Markdown("""
|
| 199 |
+
**Instrucciones de uso:**
|
| 200 |
+
- Aplica filtros por género, edad, localidad y antecedentes.
|
| 201 |
+
- Visualiza mapas con o sin capas ambientales.
|
| 202 |
+
- Compara variables clínicas por localidad.
|
| 203 |
+
- Todos los análisis son descriptivos, sin inferencia causal directa.
|
|
|
|
|
|
|
| 204 |
""")
|
| 205 |
|
| 206 |
demo.launch()
|