File size: 7,889 Bytes
290c3fd |
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 |
import streamlit as st
import pandas as pd
import folium
from folium.plugins import MarkerCluster, Search
from streamlit_folium import st_folium
import html
import io
# --- Configuraci贸n ---
st.set_page_config(page_title="Puntajes SIMCE 2024 - Centros Escolares", page_icon=":school:", layout="wide")
st.title(":school: Puntajes SIMCE 2024 - 2do Medio")
st.markdown("Explora los puntajes SIMCE de los establecimientos educacionales en Chile (Datos del MINEDUC)")
# --- Diccionarios para mapear valores a descripciones ---
dependencia_map = {
1: 'Municipal Corporaci贸n',
2: 'Municipal DAEM',
3: 'Particular subvencionado',
4: 'Particular pagado',
5: 'Corporaci贸n de administraci贸n delegada',
6: 'Servicio Local de Educaci贸n'
}
socioecon_map = {
1: 'Bajo',
2: 'Medio Bajo',
3: 'Medio',
4: 'Medio Alto',
5: 'Alto'
}
rural_map = {
1: 'Urbano',
2: 'Rural'
}
# --- Cargar datos ---
@st.cache_data
def load_data():
df = pd.read_csv(
"data/simce.csv",
sep=";",
decimal=",",
encoding="ISO-8859-1",
header=0,
on_bad_lines="skip"
)
# Crear columnas con descripciones
df['dependencia_desc'] = df['dependencia'].map(dependencia_map)
df['grupo_socioecon_desc'] = df['grupo_socioecon'].map(socioecon_map)
df['es_rural_desc'] = df['es_rural'].map(rural_map)
return df
# Cargar datos
df = load_data()
# --- Filtros ---
st.subheader("Filtros de B煤squeda")
col1, col2, col3, col4 = st.columns(4)
regiones = ["(Todas)"] + sorted(df["nombre_region"].dropna().unique().tolist())
ruralidades = ["(Todas)"] + sorted(df["es_rural_desc"].dropna().unique().tolist())
dependencias = ["(Todas)"] + sorted(df["dependencia_desc"].dropna().unique().tolist())
socioecons = ["(Todas)"] + sorted(df["grupo_socioecon_desc"].dropna().unique().tolist())
with col1:
sel_region = st.selectbox("Regi贸n", regiones, index=0, help="Selecciona una regi贸n para filtrar los establecimientos.")
with col2:
sel_ruralidad = st.selectbox("Ruralidad", ruralidades, index=0, help="Filtra por tipo de 谩rea (urbana o rural).")
with col3:
sel_dependencia = st.selectbox("Dependencia", dependencias, index=0, help="Filtra por tipo de establecimiento.")
with col4:
sel_socioecon = st.selectbox("Grupo Socioecon贸mico", socioecons, index=0, help="Filtra por nivel socioecon贸mico.")
# Filtrar datos
df_f = df.copy()
if sel_region != "(Todas)":
df_f = df_f[df_f["nombre_region"] == sel_region]
if sel_ruralidad != "(Todas)":
df_f = df_f[df_f["es_rural_desc"] == sel_ruralidad]
if sel_dependencia != "(Todas)":
df_f = df_f[df_f["dependencia_desc"] == sel_dependencia]
if sel_socioecon != "(Todas)":
df_f = df_f[df_f["grupo_socioecon_desc"] == sel_socioecon]
# Filtrar filas con coordenadas v谩lidas
df_map = df_f.dropna(subset=["latitud", "longitud"])
# --- Estad铆sticas resumidas ---
st.subheader("Estad铆sticas Resumidas")
if not df_map.empty:
col_stats1, col_stats2 = st.columns(2)
with col_stats1:
st.metric("N煤mero de Establecimientos", len(df_map))
st.metric("Promedio Lenguaje", f"{df_map['promedio_lectura'].mean():.1f}")
with col_stats2:
st.metric("Promedio Matem谩ticas", f"{df_map['promedio_matematica'].mean():.1f}")
st.metric("Regiones Cubiertas", df_map["nombre_region"].nunique())
else:
st.warning("No hay datos disponibles con los filtros seleccionados.")
# --- Mapeo de colores por tipo ---
color_map = {
'Municipal Corporaci贸n': 'blue',
'Municipal DAEM': 'green',
'Particular subvencionado': 'orange',
'Particular pagado': 'purple',
'Corporaci贸n de administraci贸n delegada': 'red',
'Servicio Local de Educaci贸n': 'cadetblue'
}
# Funci贸n para asignar color seg煤n tipo
def tipo_color(tipo: str) -> str:
return color_map.get(tipo, "gray")
# --- Crear mapa centrado en Chile ---
m = folium.Map(location=[-33.45, -70.65], zoom_start=6, tiles="CartoDB positron")
# Cluster
cluster = MarkerCluster().add_to(m)
# --- Agregar b煤squeda por nombre de colegio ---
school_search = Search(
layer=cluster,
search_label="nombre_colegio",
placeholder="Buscar por nombre del colegio...",
collapsed=False,
).add_to(m)
# --- Agregar marcadores ---
for _, r in df_map.iterrows():
lat, lon = float(r["latitud"]), float(r["longitud"])
nombre = html.escape(str(r.get("nombre_colegio", "")))
comuna = html.escape(str(r.get("nombre_comuna", "")))
tipo = html.escape(str(r.get("dependencia_desc", "")))
lenguaje = html.escape(str(r.get("promedio_lectura", "")))
matematica = html.escape(str(r.get("promedio_matematica", "")))
rural = html.escape(str(r.get("es_rural_desc", "")))
grupoeconomico = html.escape(str(r.get("grupo_socioecon_desc", "")))
popup_html = f"""
<b>{nombre}</b><br>
<b>Tipo:</b> {tipo}<br>
<b>Comuna:</b> {comuna}<br>
<b>Promedio Lenguaje:</b> {lenguaje}<br>
<b>Promedio Matem谩ticas:</b> {matematica}<br>
<b>Es Rural:</b> {rural}<br>
<b>Grupo Socioecon贸mico:</b> {grupoeconomico}
"""
marker = folium.Marker(
location=[lat, lon],
popup=folium.Popup(popup_html, max_width=350),
icon=folium.Icon(color=tipo_color(r.get("dependencia_desc")), icon="plus", prefix="fa"),
)
marker.add_to(cluster)
marker.properties = {"nombre_colegio": nombre} # Para b煤squeda
# --- Leyenda mejorada ---
legend_html = """
<div style="
position: fixed;
bottom: 30px; left: 30px; z-index: 9999;
background: white; padding: 12px; border: 2px solid #ccc; border-radius: 10px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1); font-family: Arial, sans-serif; font-size: 14px;">
<b style="color:black; font-size: 16px;">Leyenda</b><br>
<span style="display:inline-block;width:14px;height:14px;border-radius:50%;background:blue;margin-right:8px;"></span><span style="color:black;">Municipal Corporaci贸n</span><br>
<span style="display:inline-block;width:14px;height:14px;border-radius:50%;background:green;margin-right:8px;"></span><span style="color:black;">Municipal DAEM</span><br>
<span style="display:inline-block;width:14px;height:14px;border-radius:50%;background:orange;margin-right:8px;"></span><span style="color:black;">Particular subvencionado</span><br>
<span style="display:inline-block;width:14px;height:14px;border-radius:50%;background:purple;margin-right:8px;"></span><span style="color:black;">Particular pagado</span><br>
<span style="display:inline-block;width:14px;height:14px;border-radius:50%;background:red;margin-right:8px;"></span><span style="color:black;">Corporaci贸n de administraci贸n delegada</span><br>
<span style="display:inline-block;width:14px;height:14px;border-radius:50%;background:cadetblue;margin-right:8px;"></span><span style="color:black;">Servicio Local de Educaci贸n</span><br>
<span style="display:inline-block;width:14px;height:14px;border-radius:50%;background:gray;margin-right:8px;"></span><span style="color:black;">Otros</span>
</div>
"""
m.get_root().html.add_child(folium.Element(legend_html))
# --- Bot贸n para reiniciar mapa ---
if st.button("Reiniciar Mapa"):
m = folium.Map(location=[-33.45, -70.65], zoom_start=6, tiles="CartoDB positron")
st.experimental_rerun()
# --- Mostrar el mapa ---
st_folium(m, width=1200, height=650)
# --- Vista de tabla y exportaci贸n ---
with st.expander("Ver tabla filtrada"):
columns_to_display = ['nombre_region', 'nombre_comuna', 'nombre_colegio', 'dependencia_desc', 'grupo_socioecon_desc', 'es_rural_desc', 'promedio_lectura', 'promedio_matematica']
st.dataframe(df_map[columns_to_display])
# Exportar datos filtrados
csv = df_map[columns_to_display].to_csv(index=False)
st.download_button(
label="Descargar datos filtrados como CSV",
data=csv,
file_name="simce_filtrado.csv",
mime="text/csv",
) |