File size: 12,133 Bytes
229f907
 
 
 
 
 
 
 
963bfd6
 
 
 
229f907
963bfd6
229f907
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
963bfd6
 
 
 
 
 
229f907
 
 
 
963bfd6
229f907
 
 
 
963bfd6
229f907
 
963bfd6
229f907
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
963bfd6
229f907
963bfd6
229f907
 
963bfd6
 
 
 
 
 
 
 
 
 
229f907
963bfd6
 
 
 
229f907
963bfd6
 
 
 
229f907
 
963bfd6
 
 
229f907
963bfd6
 
 
 
 
 
229f907
963bfd6
 
 
 
 
 
229f907
963bfd6
229f907
 
963bfd6
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
"""
Standalone Gradio App: Rutas del Hub a Municipios
------------------------------------------------
* Datos CSV embebidos (110 filas) con columnas:
  Departamento, Ciudad, Línea, Áreas Únicas
* Si no existen columnas lat/lon, geocodifica con geopy
* No necesita archivos externos
"""

import pandas as pd
import folium
import gradio as gr
import io

try:
    from geopy.geocoders import Nominatim
    from geopy.extra.rate_limiter import RateLimiter
except ImportError:
    Nominatim = None  # geopy no instalada

# ============ CONFIGURACIÓN =============
DATA_CSV = """Departamento,Ciudad,Línea,Áreas Únicas
ANTIOQUIA,CAÑASGORDAS,Línea 1,"ARTES VISUALES Y PLÁSTICAS, DANZA, LITERATURA, MÚSICA, OTRA"
ANTIOQUIA,LA CEJA,BIAC,Sin información (no registrada en BD)
ANTIOQUIA,MEDELLÍN,BIAC,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, CIRCO, DANZA, LITERATURA, OTRA, TEATRO"
ANTIOQUIA,MEDELLÍN,Línea 1,
ANTIOQUIA,MEDELLÍN,Línea 2,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, DANZA, MÚSICA, TEATRO"
"ARCHIPIÉLAGO DE SAN ANDRÉS, PROVIDENCIA Y SANTA CATALINA",SAN ANDRÉS,Línea 1,"ARTES VISUALES Y PLÁSTICAS, LITERATURA, TEATRO"
ATLÁNTICO,BARANOA,Línea 1,"DANZA, MÚSICA, TEATRO"
ATLÁNTICO,BARRANQUILLA,BIAC,"ARTES VISUALES Y PLÁSTICAS, DANZA, LITERATURA, MÚSICA, TEATRO, TÍTERES"
ATLÁNTICO,BARRANQUILLA,Línea 2,
ATLÁNTICO,PUERTO COLOMBIA,Línea 2,"ARTES VISUALES Y PLÁSTICAS, CIRCO, DANZA, MÚSICA, TEATRO, TÍTERES"
ATLÁNTICO,SABANALARGA,BIAC,Sin información (no registrada en BD)
ATLÁNTICO,SANTO TOMÁS,Línea 2,"ARTES VISUALES Y PLÁSTICAS, DANZA, LITERATURA, TÍTERES"
ATLÁNTICO,SOLEDAD,BIAC,Sin información (no registrada en BD)
"BOGOTÁ, D.C.","BOGOTÁ, D.C.",BIAC,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, DANZA, LITERATURA, MÚSICA, OTRA, TEATRO, TÍTERES"
"BOGOTÁ, D.C.","BOGOTÁ, D.C.",Línea 1,
"BOGOTÁ, D.C.","BOGOTÁ, D.C.",Línea 2,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, CIRCO, DANZA, LITERATURA, MÚSICA, TEATRO, TÍTERES"
BOLÍVAR,CARTAGENA DE INDIAS,Línea 1,"ARTES VISUALES Y PLÁSTICAS, LITERATURA, MÚSICA"
BOLÍVAR,CARTAGENA DE INDIAS,Línea 2,"ARTES VISUALES Y PLÁSTICAS, CIRCO, DANZA, LITERATURA, MÚSICA, TEATRO, TÍTERES"
BOLÍVAR,MAHATES,Línea 2,"AUDIOVISUALES, DANZA, LITERATURA, MÚSICA, OTRA"
BOLÍVAR,SAN JACINTO,Línea 1,"DANZA, MÚSICA, TEATRO"
BOLÍVAR,SAN JACINTO,Línea 2,"DANZA, LITERATURA, MÚSICA, TEATRO"
BOLÍVAR,SAN JUAN NEPOMUCENO,Línea 2,"CIRCO, DANZA, MÚSICA, TEATRO"
BOLÍVAR,SOPLAVIENTO,Línea 1,"ARTES VISUALES Y PLÁSTICAS, DANZA, MÚSICA"
BOLÍVAR,TURBACO,Línea 1,"ARTES VISUALES Y PLÁSTICAS, DANZA, MÚSICA"
BOYACÁ,CHIQUINQUIRÁ,Línea 1,"ARTES VISUALES Y PLÁSTICAS, LITERATURA, OTRA"
BOYACÁ,DUITAMA,Línea 1,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, CIRCO, DANZA, LITERATURA, MÚSICA, TEATRO, TÍTERES"
BOYACÁ,GACHANTIVÁ,BIAC,Sin información (no registrada en BD)
BOYACÁ,SOGAMOSO,Línea 1,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, DANZA, MÚSICA, TEATRO"
BOYACÁ,TUNJA,Línea 2,"ARTES VISUALES Y PLÁSTICAS, TEATRO, TÍTERES"
BOYACÁ,VILLA DE LEYVA,Línea 1,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, OTRA"
CALDAS,ANSERMA,Línea 2,"ARTES VISUALES Y PLÁSTICAS, DANZA, LITERATURA, MÚSICA, OTRA, TEATRO"
CALDAS,MANIZALES,Línea 1,"AUDIOVISUALES, DANZA, LITERATURA, MÚSICA, TEATRO, TÍTERES"
CALDAS,SAMANÁ,Línea 1,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, DANZA, TEATRO"
CAQUETÁ,CARTAGENA DEL CHAIRÁ,BIAC,Sin información (no registrada en BD)
CAQUETÁ,FLORENCIA,Línea 2,"DANZA, LITERATURA, MÚSICA, TEATRO"
CAQUETÁ,LA MONTAÑITA,BIAC,"ARTES VISUALES Y PLÁSTICAS, MÚSICA, OTRA, TEATRO"
CAQUETÁ,LA MONTAÑITA,Línea 2,
CAUCA,INZÁ,Línea 2,"DANZA, MÚSICA, OTRA, TEATRO, TÍTERES"
CAUCA,MERCADERES,BIAC,Sin información (no registrada en BD)
CAUCA,POPAYÁN,BIAC,"DANZA, LITERATURA, MÚSICA, TEATRO"
CAUCA,POPAYÁN,Línea 1,
CAUCA,POPAYÁN,Línea 2,"DANZA, LITERATURA, MÚSICA, OTRA"
CAUCA,PUERTO TEJADA,BIAC,"ARTES VISUALES Y PLÁSTICAS, DANZA, MÚSICA"
CAUCA,PUERTO TEJADA,Línea 1,
CAUCA,SAN SEBASTIÁN,Línea 1,"DANZA, MÚSICA, TEATRO"
CESAR,LA JAGUA DE IBIRICO,Línea 2,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, DANZA, LITERATURA, MÚSICA, TEATRO, TÍTERES"
CHOCÓ,CONDOTO,Línea 1,"MÚSICA, TEATRO"
CHOCÓ,ISTMINA,BIAC,Sin información (no registrada en BD)
CUNDINAMARCA,CHOACHÍ,Línea 2,"ARTES VISUALES Y PLÁSTICAS, DANZA, LITERATURA, MÚSICA"
CUNDINAMARCA,SOACHA,BIAC,Sin información (no registrada en BD)
CUNDINAMARCA,SOPÓ,Línea 1,"MÚSICA, TEATRO, TÍTERES"
CUNDINAMARCA,TABIO,Línea 1,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, MÚSICA"
CUNDINAMARCA,TENJO,Línea 1,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, DANZA, MÚSICA"
CÓRDOBA,CERETÉ,BIAC,Sin información (no registrada en BD)
CÓRDOBA,MONTERÍA,Línea 1,"ARTES VISUALES Y PLÁSTICAS, LITERATURA, TEATRO"
CÓRDOBA,PUERTO LIBERTADOR,BIAC,Sin información (no registrada en BD)
CÓRDOBA,SAHAGÚN,Línea 2,"ARTES VISUALES Y PLÁSTICAS, LITERATURA, OTRA, TEATRO"
GUAVIARE,SAN JOSÉ DEL GUAVIARE,BIAC,Sin información (no registrada en BD)
HUILA,ALGECIRAS,Línea 1,"DANZA, MÚSICA, TEATRO"
HUILA,GARZÓN,Línea 1,"DANZA, LITERATURA, MÚSICA"
HUILA,NEIVA,Línea 1,"DANZA, LITERATURA, MÚSICA"
HUILA,SAN AGUSTÍN,BIAC,Sin información (no registrada en BD)
LA GUAJIRA,MAICAO,Línea 1,"DANZA, MÚSICA, TEATRO"
LA GUAJIRA,RIOHACHA,Línea 1,"DANZA, MÚSICA, TEATRO"
LA GUAJIRA,URUMITA,Línea 2,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, DANZA, MÚSICA, TEATRO, TÍTERES"
MAGDALENA,CIÉNAGA,Línea 1,"DANZA, TEATRO, TÍTERES"
MAGDALENA,EL BANCO,Línea 1,"ARTES VISUALES Y PLÁSTICAS, MÚSICA, TEATRO"
META,SAN MARTÍN,BIAC,Sin información (no registrada en BD)
META,VILLAVICENCIO,Línea 2,"ARTES VISUALES Y PLÁSTICAS, LITERATURA, MÚSICA, OTRA"
NARIÑO,LA CRUZ,Línea 2,"ARTES VISUALES Y PLÁSTICAS, DANZA, MÚSICA, TEATRO, TÍTERES"
NARIÑO,LA TOLA,Línea 1,"DANZA, LITERATURA, MÚSICA"
NARIÑO,PASTO,BIAC,"DANZA, LITERATURA, MÚSICA"
NARIÑO,PASTO,Línea 1,"CIRCO, DANZA, MÚSICA, TEATRO, TÍTERES"
NARIÑO,PASTO,Línea 2,"LITERATURA, MÚSICA, OTRA"
NARIÑO,ROBERTO PAYÁN,Línea 1,
NARIÑO,SAN ANDRÉS DE TUMACO,Línea 1,"ARTES VISUALES Y PLÁSTICAS, DANZA, MÚSICA"
NORTE DE SANTANDER,SAN JOSÉ DE CÚCUTA,Línea 2,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, CIRCO, DANZA, LITERATURA, MÚSICA, OTRA, TEATRO, TÍTERES"
PUTUMAYO,SAN FRANCISCO,Línea 1,"DANZA, MÚSICA, OTRA"
PUTUMAYO,SIBUNDOY,Línea 1,"AUDIOVISUALES, MÚSICA, OTRA"
QUINDÍO,ARMENIA,BIAC,"ARTES VISUALES Y PLÁSTICAS, LITERATURA, MÚSICA"
QUINDÍO,ARMENIA,Línea 1,
QUINDÍO,BUENAVISTA,Línea 1,"LITERATURA, MÚSICA, TEATRO"
QUINDÍO,MONTENEGRO,BIAC,Sin información (no registrada en BD)
RISARALDA,PEREIRA,BIAC,"ARTES VISUALES Y PLÁSTICAS, DANZA, LITERATURA, MÚSICA, TEATRO"
RISARALDA,PEREIRA,Línea 1,
RISARALDA,PEREIRA,Línea 2,"ARTES VISUALES Y PLÁSTICAS, DANZA, LITERATURA, MÚSICA, TEATRO"
SANTANDER,BARRANCABERMEJA,Línea 2,"CIRCO, MÚSICA, TEATRO, TÍTERES"
SANTANDER,BUCARAMANGA,BIAC,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, DANZA, LITERATURA, MÚSICA, TEATRO"
SANTANDER,BUCARAMANGA,Línea 1,
SANTANDER,SAN VICENTE DE CHUCURÍ,Línea 1,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, LITERATURA, OTRA"
SUCRE,COROZAL,Línea 1,"DANZA, LITERATURA, MÚSICA"
SUCRE,SAMPUÉS,Línea 2,"ARTES VISUALES Y PLÁSTICAS, DANZA, LITERATURA, MÚSICA"
SUCRE,SAN JOSÉ DE TOLUVIEJO,Línea 1,"DANZA, LITERATURA, MÚSICA"
SUCRE,SINCELEJO,Línea 1,"DANZA, LITERATURA, MÚSICA"
SUCRE,SINCELEJO,Línea 2,"ARTES VISUALES Y PLÁSTICAS, DANZA, MÚSICA, TEATRO"
TOLIMA,IBAGUÉ,Línea 1,"LITERATURA, MÚSICA, TEATRO, TÍTERES"
VALLE DEL CAUCA,BUENAVENTURA,Línea 2,"ARTES VISUALES Y PLÁSTICAS, DANZA, LITERATURA, TEATRO"
VALLE DEL CAUCA,CAICEDONIA,Línea 1,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, LITERATURA"
VALLE DEL CAUCA,CALIMA,Línea 1,"ARTES VISUALES Y PLÁSTICAS, MÚSICA, TEATRO"
VALLE DEL CAUCA,FLORIDA,BIAC,Sin información (no registrada en BD)
VALLE DEL CAUCA,GUACARÍ,Línea 2,"DANZA, LITERATURA, MÚSICA, TEATRO"
VALLE DEL CAUCA,GUADALAJARA DE BUGA,Línea 2,"ARTES VISUALES Y PLÁSTICAS, LITERATURA, TEATRO, TÍTERES"
VALLE DEL CAUCA,LA CUMBRE,Línea 2,"ARTES VISUALES Y PLÁSTICAS, DANZA, MÚSICA, TEATRO"
VALLE DEL CAUCA,RIOFRÍO,BIAC,Sin información (no registrada en BD)
VALLE DEL CAUCA,SAN PEDRO,Línea 1,"ARTES VISUALES Y PLÁSTICAS, DANZA, MÚSICA"
VALLE DEL CAUCA,SANTIAGO DE CALI,BIAC,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, DANZA, LITERATURA, MÚSICA, TEATRO"
VALLE DEL CAUCA,SANTIAGO DE CALI,Línea 1,
VALLE DEL CAUCA,SANTIAGO DE CALI,Línea 2,"ARTES VISUALES Y PLÁSTICAS, DANZA, LITERATURA, MÚSICA, OTRA, TEATRO"
VALLE DEL CAUCA,SEVILLA,Línea 1,"ARTES VISUALES Y PLÁSTICAS, AUDIOVISUALES, DANZA, MÚSICA, TEATRO"
VALLE DEL CAUCA,TULUÁ,Línea 1,"CIRCO, DANZA, MÚSICA"
"""

HUB_NAME = "Bogotá"
HUB_LAT, HUB_LON = 4.7110, -74.0721

LINE_COLOR = {
    "Línea 1": "red",
    "Línea 2": "blue",
    "BIAC": "green"
}
# =========================================

# Leer DataFrame
df = pd.read_csv(io.StringIO(DATA_CSV))

# ------------ Geocodificar ---------------
def geocode_missing(dframe: pd.DataFrame) -> pd.DataFrame:
    if {'lat','lon'}.issubset(dframe.columns) and not dframe[['lat','lon']].isna().any().any():
        return dframe

    if Nominatim is None:
        raise ImportError("Faltan 'lat' y 'lon' y geopy no está instalado.")

    geolocator = Nominatim(user_agent="clanes_mapa_app")
    geocode = RateLimiter(geolocator.geocode, min_delay_seconds=1)

    if 'lat' not in dframe.columns:
        dframe['lat'] = pd.NA
        dframe['lon'] = pd.NA

    cache = {}
    for i, row in dframe.iterrows():
        if not pd.isna(row['lat']) and not pd.isna(row['lon']):
            continue
        key = (row['Ciudad'], row['Departamento'])
        if key in cache:
            lat, lon = cache[key]
        else:
            loc = geocode(f"{row['Ciudad']}, {row['Departamento']}, Colombia")
            lat, lon = (loc.latitude, loc.longitude) if loc else (pd.NA, pd.NA)
            cache[key] = (lat, lon)
        dframe.at[i, 'lat'] = lat
        dframe.at[i, 'lon'] = lon
    return dframe

df = geocode_missing(df)

# --------- Helpers para filtros ----------
def explode_areas(series, sep=','):
    return {a.strip() for sub in series.dropna() for a in str(sub).split(sep)}

all_areas = sorted(explode_areas(df['Áreas Únicas']))
all_areas.insert(0, "Todas")
all_lines = ["Todas"] + sorted(df['Línea'].dropna().unique().tolist())

# -------------- Mapa ---------------------
def make_map(selected_area: str, selected_line: str) -> str:
    m = folium.Map(location=[HUB_LAT, HUB_LON], zoom_start=6, tiles="cartodbpositron")

    folium.Marker(
        [HUB_LAT, HUB_LON],
        tooltip=f"Hub: {HUB_NAME}",
        icon=folium.Icon(color='orange', icon='home')
    ).add_to(m)

    filt = df.copy()
    if selected_line != "Todas":
        filt = filt[filt['Línea'] == selected_line]
    if selected_area != "Todas":
        filt = filt[filt['Áreas Únicas'].str.contains(selected_area, case=False, na=False)]

    for _, row in filt.iterrows():
        lat, lon = row.get('lat'), row.get('lon')
        if pd.isna(lat) or pd.isna(lon):
            continue
        folium.Marker(
            [lat, lon],
            tooltip=(f"{row['Ciudad']}{row['Línea']}\nÁreas: {row['Áreas Únicas']}"),
            icon=folium.Icon(color='blue', icon='user')
        ).add_to(m)
        folium.PolyLine(
            [[HUB_LAT, HUB_LON], [lat, lon]],
            color=LINE_COLOR.get(row['Línea'], 'gray'),
            weight=2,
            opacity=0.8
        ).add_to(m)

    return m._repr_html_()

# -------------- Interface -----------------
demo = gr.Interface(
    fn=make_map,
    inputs=[
        gr.Dropdown(choices=all_areas, value="Todas", label="Filtrar por Área"),
        gr.Dropdown(choices=all_lines, value="Todas", label="Filtrar por Línea")
    ],
    outputs=gr.HTML(label="Mapa"),
    title="Mapa de Rutas: Hub → Municipios",
    description="Filtra por Área artística y/o Línea para visualizar las rutas.",
    allow_flagging="never"
)

if __name__ == "__main__":
    demo.launch()