Saltar al contenido

# visualizacion-geospacial-avanzada-con-geopandas

Visualización Geospacial Avanzada con GeoPandas

Volver a la portada del curso
Lectura (Markdown)

Uso de Matplotlib con GeoPandas

Sección 4 · Integración con Pandas y Matplotlib

Uso de Matplotlib con GeoPandas

GeoDataFrame.plot() dibuja con Matplotlib, así que todo lo que sabes de Matplotlib sirve para tus mapas: ejes, títulos, anotaciones, subgráficos y estilos. La diferencia es que cada capa del mapa es una llamada a plot() sobre los mismos ejes. Esta lección construye mapas temáticos completos con los estados y las ciudades de México.

Preparar los datos

Cargamos los estados y las ciudades de Natural Earth, limpiamos la capa de estados y proyectamos todo a EPSG:6372, un CRS en metros pensado para México:

import geopandas as gpd
import matplotlib.pyplot as plt

NE = "https://naciscdn.org/naturalearth/10m/cultural/"
estados = gpd.read_file(NE + "ne_10m_admin_1_states_provinces.zip",
                        where="iso_a2 = 'MX'", columns=["name", "iso_a2"])
estados = estados.dropna(subset=["name"]).to_crs(6372)
estados["name"] = estados["name"].replace({"Distrito Federal": "Ciudad de México"})
ciudades = gpd.read_file(NE + "ne_10m_populated_places_simple.zip",
                         where="iso_a2 = 'MX'",
                         columns=["name", "pop_max", "iso_a2"]).to_crs(6372)
ciudades["name"] = ciudades["name"].replace({"Mexico City": "Ciudad de México"})
print(len(estados), "estados,", len(ciudades), "ciudades")

Natural Earth escribe algunos nombres en inglés, como «Mexico City»; conviene corregirlos antes de usarlos como etiquetas.

Capas sobre los mismos ejes

La regla es crear los ejes una vez y pasar ax=ax a cada capa. El orden de las llamadas es el orden de apilado: primero el fondo, al final los puntos y los textos.

fig, ax = plt.subplots(figsize=(10, 7))
estados.plot(ax=ax, color="#eeeeee", edgecolor="gray", linewidth=0.4)
grandes = ciudades.nlargest(10, "pop_max")
grandes.plot(ax=ax, color="crimson", markersize=grandes.pop_max / 4e4,
             alpha=0.7, edgecolor="black", linewidth=0.3)
for _, c in grandes.head(3).iterrows():
    ax.annotate(c["name"], xy=(c.geometry.x, c.geometry.y),
                xytext=(5, 5), textcoords="offset points", fontsize=9)
ax.set_title("Las 10 ciudades más pobladas de México")
ax.set_axis_off()
fig.savefig("ciudades.png", dpi=150, bbox_inches="tight")

markersize acepta una columna, así el tamaño del punto codifica la población. set_axis_off() quita las coordenadas en metros del CRS proyectado, que no aportan nada al lector.

Mapas de coropletas

Una coropleta colorea cada polígono según un valor. Basta con column; con legend=True aparece la barra de color. Una regla importante: colorea tasas o densidades, no totales. Un estado grande acumula más de todo solo por su tamaño, y el color terminaría mostrando el área. Para practicar la mecánica usamos la superficie misma, una propiedad de cada polígono; en el proyecto final colorearás una densidad.

estados["area_km2"] = estados.area / 1e6
ax = estados.plot(column="area_km2", cmap="viridis", legend=True,
                  edgecolor="white", linewidth=0.3, figsize=(10, 6),
                  legend_kwds={"label": "Superficie (km²)", "shrink": 0.6})
ax.set_title("Superficie por estado")
ax.set_axis_off()

Esquemas de clasificación

Con una escala continua, un valor extremo puede aplastar al resto. El parámetro scheme (requiere la biblioteca mapclassify) agrupa los valores en k clases y cambia por completo la lectura del mapa:

  • "Quantiles": el mismo número de estados en cada clase. Muestra el orden, pero puede juntar valores muy distintos.
  • "EqualInterval": clases del mismo ancho. Con un valor extremo, casi todo cae en la primera clase.
  • "NaturalBreaks" (Jenks): busca cortes donde los datos se separan de forma natural. Usa un algoritmo con inicios aleatorios, así que dos ejecuciones pueden dar clases un poco distintas; si necesitas resultados reproducibles, usa "FisherJenks", que calcula los cortes óptimos de forma exacta.
fig, axes = plt.subplots(1, 3, figsize=(16, 4.5))
for ax, esquema in zip(axes, ["Quantiles", "EqualInterval", "NaturalBreaks"]):
    estados.plot(column="area_km2", scheme=esquema, k=5, cmap="YlGnBu",
                 edgecolor="gray", linewidth=0.3, ax=ax, legend=True,
                 legend_kwds={"loc": "lower left", "fontsize": 7})
    ax.set_title(esquema)
    ax.set_axis_off()
fig.savefig("esquemas.png", dpi=120, bbox_inches="tight")

Valores faltantes

Si algún polígono no tiene dato, por omisión no se dibuja y el mapa queda con huecos que parecen errores. missing_kwds los muestra con un estilo propio, por ejemplo gris con rayas y la etiqueta «Sin datos» en la leyenda:

estados.loc[estados["name"] == "Oaxaca", "area_km2"] = None
ax = estados.plot(column="area_km2", cmap="viridis", legend=True,
                  missing_kwds={"color": "lightgray", "hatch": "///",
                                "label": "Sin datos"})
ax.set_axis_off()

Trampas comunes

  • Coropletas de totales. Normaliza por área o por población antes de colorear.
  • Dibujar en grados con la forma equivocada. En EPSG:4326 el mapa de México sale estirado; proyecta para dibujar.
  • Olvidar ax=ax. Cada capa termina en su propia figura.
  • Paletas arcoíris. jet crea fronteras visuales falsas; usa viridis, YlGnBu o paletas divergentes si hay un centro con sentido.
  • Leyendas sin unidades. Escribe siempre qué se mide y en qué unidad.

Cierre

Un buen mapa temático responde una sola pregunta. Elige la variable (mejor una tasa), el esquema de clases que la cuente con honestidad y una paleta legible; después agrega solo el contexto que ayude a leerla.