hedtorresca commited on
Commit
9785388
·
verified ·
1 Parent(s): c035b8b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +25 -108
app.py CHANGED
@@ -11,41 +11,33 @@ import io
11
  import base64
12
  import folium
13
  from folium.plugins import HeatMap
 
14
  import os
15
 
16
  # =========================
17
- # 1. CARGA DE DATOS
18
  # =========================
19
  data = pd.read_csv("VasculitisAsociadasA-BDD10jul24_DATA_2025-03-19_1033.csv")
20
  data.columns = data.columns.str.strip().str.lower()
21
 
22
- # Identificar y renombrar columna de localidad
23
- col_localidad = next((col for col in data.columns if 'localidad' in col), None)
24
- if col_localidad:
25
- data.rename(columns={col_localidad: 'localidad'}, inplace=True)
26
- data['localidad'] = data['localidad'].astype(str).str.upper()
27
- else:
28
- data['localidad'] = "SIN DATO"
29
-
30
- # Carga GeoJSONs ambientales y localidades
31
  geo_localidades = gpd.read_file("loca.json")
32
- geo_localidades.columns = geo_localidades.columns.str.strip()
33
- if 'LocNombre' in geo_localidades.columns:
34
- geo_localidades['localidad'] = geo_localidades['LocNombre'].str.upper()
35
  else:
36
- raise ValueError("El GeoJSON de localidades no tiene la columna 'LocNombre'")
37
-
38
- capas_ambientales = {
39
- 'pm25': gpd.read_file("pm25_prom_anual_2023.geojson"),
40
- 'ozono': gpd.read_file("ozono_prom_anual_2022.geojson"),
41
- 'temperatura': gpd.read_file("temp_anualprom_2023.geojson"),
42
- 'precipitacion': gpd.read_file("precip_anualacum_2023.geojson"),
43
- 'viento': gpd.read_file("vel_viento_0_23h_anual_2023.geojson"),
44
- 'estaciones': gpd.read_file("estacion_calidad_aire.geojson")
45
- }
46
 
47
  # =========================
48
- # 2. PROCESAMIENTO DE DATOS
49
  # =========================
50
  categorias = {
51
  'genero_cat': data['genero'].map({0: 'Masculino', 1: 'Femenino'}),
@@ -54,96 +46,21 @@ categorias = {
54
  }
55
  data = data.assign(**categorias)
56
 
57
- # ANCA positivo
58
  data['anca_cat'] = data['ancas'].map({0: 'Negativo', 1: 'Positivo'}).fillna('No definido')
59
  data['mpo_cat'] = data['mpo'].map({0: 'Negativo', 1: 'Positivo'}).fillna('No definido')
60
  data['pr3_cat'] = data['pr3'].map({0: 'Negativo', 1: 'Positivo'}).fillna('No definido')
61
 
62
- # Biopsia
63
  biopsia_cols = [col for col in data.columns if col.startswith('biopsia___')]
64
  data['biopsia_positiva'] = data[biopsia_cols].sum(axis=1).apply(lambda x: 'Sí' if x > 0 else 'No')
65
  data['anca_y_renal'] = np.where((data['ancas'] == 1) & (data['biopsia_positiva'] == 'Sí'), 'Sí', 'No')
66
 
67
  # =========================
68
- # 3. FILTRADO DINÁMICO
69
- # =========================
70
- def aplicar_filtros(df, genero, edad, localidad, anca_tipo, antecedentes):
71
- if genero != "Todos":
72
- df = df[df['genero_cat'] == genero]
73
- df = df[(df['edad'] >= edad[0]) & (df['edad'] <= edad[1])]
74
- if localidad:
75
- df = df[df['localidad'].isin(localidad)]
76
- if anca_tipo != "Todos":
77
- df = df[df['anca_cat'] == anca_tipo]
78
- for ant in antecedentes:
79
- if ant in df.columns:
80
- df = df[df[ant] == 1]
81
- return df
82
-
83
- # =========================
84
- # 4. MAPA COROPLÉTICO CON CAPAS AMBIENTALES
85
- # =========================
86
- def generar_mapa_coropletico(df_filtrado):
87
- conteo = df_filtrado.groupby('localidad').size().reset_index(name='casos')
88
- geo_merged = geo_localidades.merge(conteo, on='localidad', how='left').fillna(0)
89
- fig = px.choropleth_mapbox(
90
- geo_merged,
91
- geojson=geo_merged.geometry,
92
- locations=geo_merged.index,
93
- color='casos',
94
- hover_name='localidad',
95
- mapbox_style='carto-positron',
96
- zoom=10,
97
- center={"lat": 4.65, "lon": -74.1},
98
- opacity=0.6
99
- )
100
- return fig
101
-
102
- # =========================
103
- # 5. ANÁLISIS DESCRIPTIVO
104
  # =========================
105
- def generar_univariado():
106
- rutas = []
107
- variables_uni = ['edad', 'genero_cat', 'regimen_cat', 'estrato_cat', 'anca_cat',
108
- 'mpo_cat', 'pr3_cat', 'biopsia_positiva', 'anca_y_renal', 'sindrome',
109
- 'diabetes', 'falla_cardiaca', 'epoc', 'hta']
110
- for col in variables_uni:
111
- plt.figure(figsize=(6, 4))
112
- if data[col].dtype == 'object':
113
- sns.countplot(data=data, x=col, order=data[col].value_counts().index)
114
- else:
115
- sns.histplot(data[col], kde=True)
116
- plt.title(f"Distribución de {col}")
117
- plt.xticks(rotation=30)
118
- plt.tight_layout()
119
- path = f"uni_{col}.png"
120
- plt.savefig(path)
121
- rutas.append(path)
122
- plt.close()
123
- return rutas
124
-
125
- def generar_bivariado():
126
- relaciones_bi = [
127
- ('anca_cat', 'biopsia_positiva'), ('anca_cat', 'mpo_cat'),
128
- ('anca_cat', 'pr3_cat'), ('estrato_cat', 'biopsia_positiva'),
129
- ('genero_cat', 'anca_cat'), ('regimen_cat', 'anca_cat'),
130
- ('sindrome', 'biopsia_positiva')
131
- ]
132
- rutas = []
133
- for x, y in relaciones_bi:
134
- plt.figure(figsize=(6, 4))
135
- sns.countplot(data=data, x=x, hue=y)
136
- plt.title(f"{x} vs {y}")
137
- plt.xticks(rotation=30)
138
- plt.tight_layout()
139
- path = f"bi_{x}_{y}.png"
140
- plt.savefig(path)
141
- rutas.append(path)
142
- plt.close()
143
- return rutas
144
 
145
  # =========================
146
- # 6. INTERFAZ DE USUARIO (GRADIO)
147
  # =========================
148
  def interfaz():
149
  with gr.Blocks() as demo:
@@ -151,22 +68,22 @@ def interfaz():
151
 
152
  genero = gr.Dropdown(label="Género", choices=["Todos", "Masculino", "Femenino"], value="Todos")
153
  edad = gr.Slider(label="Edad", minimum=0, maximum=100, value=(20, 80), step=1)
154
- localidades = gr.Dropdown(label="Localidad", choices=sorted(data['localidad'].unique()), multiselect=True)
155
- anca = gr.Dropdown(label="Tipo de ANCA", choices=["Todos", "Positivo", "Negativo"], value="Todos")
156
  antecedentes = gr.CheckboxGroup(label="Antecedentes", choices=["diabetes", "hta", "epoc", "falla_cardiaca"])
157
 
158
  boton = gr.Button("Generar Mapa")
159
  salida = gr.Plot()
160
 
161
- def actualizar(genero, edad, localidades, anca, antecedentes):
162
- filtrado = aplicar_filtros(data, genero, edad, localidades, anca, antecedentes)
163
  if filtrado.empty:
164
  fig = go.Figure()
165
  fig.update_layout(title="No hay datos para los filtros seleccionados")
166
  return fig
167
  return generar_mapa_coropletico(filtrado)
168
 
169
- boton.click(actualizar, inputs=[genero, edad, localidades, anca, antecedentes], outputs=salida)
170
 
171
  with gr.Tab("Gráficos Univariados"):
172
  for path in generar_univariado():
@@ -178,4 +95,4 @@ def interfaz():
178
 
179
  demo.launch()
180
 
181
- interfaz()
 
11
  import base64
12
  import folium
13
  from folium.plugins import HeatMap
14
+ from shapely.geometry import Point
15
  import os
16
 
17
  # =========================
18
+ # 1. CARGA DE DATOS Y LOCALIDADES
19
  # =========================
20
  data = pd.read_csv("VasculitisAsociadasA-BDD10jul24_DATA_2025-03-19_1033.csv")
21
  data.columns = data.columns.str.strip().str.lower()
22
 
23
+ # Cargar localidades
 
 
 
 
 
 
 
 
24
  geo_localidades = gpd.read_file("loca.json")
25
+ geo_localidades.columns = geo_localidades.columns.str.strip().str.lower()
26
+ if 'locnombre' in geo_localidades.columns:
27
+ geo_localidades['localidad'] = geo_localidades['locnombre'].str.upper()
28
  else:
29
+ raise ValueError("El GeoJSON de localidades no tiene la columna 'locnombre')")
30
+
31
+ # Convertir data a GeoDataFrame con lat/lon
32
+ data = data.dropna(subset=['coordenada_residencia-latitud', 'coordenada_residencia-longitud'])
33
+ data['geometry'] = data.apply(lambda row: Point(row['coordenada_residencia-longitud'], row['coordenada_residencia-latitud']), axis=1)
34
+ data = gpd.GeoDataFrame(data, geometry='geometry', crs='EPSG:4326')
35
+
36
+ # Intersección espacial para asignar localidad
37
+ data = gpd.sjoin(data, geo_localidades[['localidad', 'geometry']], how='left', predicate='within')
 
38
 
39
  # =========================
40
+ # 2. CATEGORÍAS Y VARIABLES DERIVADAS
41
  # =========================
42
  categorias = {
43
  'genero_cat': data['genero'].map({0: 'Masculino', 1: 'Femenino'}),
 
46
  }
47
  data = data.assign(**categorias)
48
 
 
49
  data['anca_cat'] = data['ancas'].map({0: 'Negativo', 1: 'Positivo'}).fillna('No definido')
50
  data['mpo_cat'] = data['mpo'].map({0: 'Negativo', 1: 'Positivo'}).fillna('No definido')
51
  data['pr3_cat'] = data['pr3'].map({0: 'Negativo', 1: 'Positivo'}).fillna('No definido')
52
 
 
53
  biopsia_cols = [col for col in data.columns if col.startswith('biopsia___')]
54
  data['biopsia_positiva'] = data[biopsia_cols].sum(axis=1).apply(lambda x: 'Sí' if x > 0 else 'No')
55
  data['anca_y_renal'] = np.where((data['ancas'] == 1) & (data['biopsia_positiva'] == 'Sí'), 'Sí', 'No')
56
 
57
  # =========================
58
+ # 3. FUNCIONES DE FILTRO Y GRÁFICOS (sin cambios)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  # =========================
60
+ # ... (mantener las funciones: aplicar_filtros, generar_mapa_coropletico, generar_univariado, generar_bivariado)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
  # =========================
63
+ # 4. INTERFAZ DE USUARIO (GRADIO)
64
  # =========================
65
  def interfaz():
66
  with gr.Blocks() as demo:
 
68
 
69
  genero = gr.Dropdown(label="Género", choices=["Todos", "Masculino", "Femenino"], value="Todos")
70
  edad = gr.Slider(label="Edad", minimum=0, maximum=100, value=(20, 80), step=1)
71
+ localidades = gr.Dropdown(label="Localidad", choices=sorted(data['localidad'].dropna().unique()), multiselect=True)
72
+ compromiso_renal = gr.Dropdown(label="Compromiso Renal", choices=["Todos", "", "No"], value="Todos")
73
  antecedentes = gr.CheckboxGroup(label="Antecedentes", choices=["diabetes", "hta", "epoc", "falla_cardiaca"])
74
 
75
  boton = gr.Button("Generar Mapa")
76
  salida = gr.Plot()
77
 
78
+ def actualizar(genero, edad, localidades, compromiso_renal, antecedentes):
79
+ filtrado = aplicar_filtros(data, genero, edad, localidades, compromiso_renal, antecedentes)
80
  if filtrado.empty:
81
  fig = go.Figure()
82
  fig.update_layout(title="No hay datos para los filtros seleccionados")
83
  return fig
84
  return generar_mapa_coropletico(filtrado)
85
 
86
+ boton.click(actualizar, inputs=[genero, edad, localidades, compromiso_renal, antecedentes], outputs=salida)
87
 
88
  with gr.Tab("Gráficos Univariados"):
89
  for path in generar_univariado():
 
95
 
96
  demo.launch()
97
 
98
+ interfaz()