tutoriales.com

Analiza Datos Geográficos con GeoPandas: Crea Mapas Temáticos en Python

Este tutorial te guiará paso a paso en el uso de GeoPandas, una potente librería de Python para trabajar con datos geoespaciales. Aprenderás a cargar, manipular y visualizar datos geográficos, creando mapas temáticos informativos y visualmente atractivos. Ideal para científicos de datos, analistas y entusiastas de la geografía.

Intermedio20 min de lectura7 views
Reportar error

🗺️ Introducción a GeoPandas: Tu Puerta al Análisis Geoespacial

El análisis de datos geográficos se ha convertido en una disciplina fundamental en una multitud de campos, desde la planificación urbana y la gestión ambiental hasta la logística y el marketing. Poder visualizar y entender cómo los datos se distribuyen en el espacio nos brinda insights únicos que los análisis tradicionales a menudo pasan por alto.

Aquí es donde entra GeoPandas, una extensión de la popular librería Pandas que facilita enormemente el trabajo con datos geoespaciales en Python. GeoPandas combina la familiaridad y eficiencia de Pandas para la manipulación de datos tabulares con las capacidades geoespaciales de librerías como Shapely para objetos geométricos y Fiona para el acceso a archivos de datos espaciales. En esencia, te permite realizar operaciones de Sistemas de Información Geográfica (SIG) directamente en tu entorno Python.

Este tutorial te equipará con los conocimientos y herramientas necesarias para empezar a explorar y visualizar tus propios datos geográficos, creando mapas temáticos que cuenten una historia.

¿Por qué GeoPandas? 🤔

Si ya estás familiarizado con Pandas, te sentirás como en casa con GeoPandas. Extiende los DataFrame y Series de Pandas para incluir una columna especial llamada geometry, que almacena objetos geométricos como puntos, líneas o polígonos. Esto permite realizar operaciones espaciales de forma intuitiva, combinándolas con las poderosas capacidades de filtrado y manipulación de datos de Pandas.

💡 Consejo: Si eres nuevo en Pandas, te recomiendo familiarizarte con los conceptos básicos de `DataFrame` y `Series` antes de sumergirte en GeoPandas para una experiencia de aprendizaje más fluida.

🛠️ Configuración del Entorno: Preparando el Terreno

Antes de empezar a escribir código, necesitamos asegurarnos de que tenemos todas las librerías necesarias instaladas. La forma más recomendada de instalar GeoPandas y sus dependencias es utilizando conda o pip.

Instalación con Conda (Recomendado) 🐍

Si utilizas Anaconda o Miniconda, la instalación es sencilla y resuelve automáticamente las dependencias, incluyendo fiona, shapely, pyproj y rtree.

conda install geopandas

Instalación con Pip (Alternativa) 📦

Si prefieres pip, ten en cuenta que puede requerir la instalación manual de algunas dependencias binarias o que tengas las herramientas de compilación adecuadas en tu sistema.

pip install geopandas

Verifica tu instalación abriendo un intérprete de Python e importando la librería:

import geopandas as gpd
print(gpd.__version__)

Si no obtienes errores y ves la versión de GeoPandas, ¡estás listo!

📖 Conceptos Clave en GeoPandas

Antes de sumergirnos en el código, es crucial entender algunos conceptos fundamentales:

GeoDataFrame y GeoSeries

Al igual que Pandas tiene DataFrame y Series, GeoPandas introduce GeoDataFrame y GeoSeries. Un GeoDataFrame es un DataFrame de Pandas que tiene una columna geometry especial. Esta columna contiene objetos Shapely que representan características geográficas (puntos, líneas, polígonos). Un GeoSeries es una Series que contiene solo objetos geométricos.

Geometrías (Shapely) 📍📏🏞️

GeoPandas utiliza la librería Shapely para manejar los objetos geométricos. Los tipos de geometrías más comunes son:

  • Point: Un único par de coordenadas (x, y).
  • LineString: Una secuencia de puntos conectados que forman una línea.
  • Polygon: Una secuencia de puntos conectados que forman un área cerrada, con un exterior y opcionalmente interiores (agujeros).
  • MultiPoint, MultiLineString, MultiPolygon: Colecciones de los tipos anteriores.

Sistemas de Coordenadas de Referencia (CRS) 🌐

El CRS (Coordinate Reference System) es vital para cualquier dato geoespacial. Define cómo las coordenadas de tus geometrías se mapean a ubicaciones en la Tierra. Es como el 'idioma' en el que están tus coordenadas. Los CRS se pueden especificar usando códigos EPSG (European Petroleum Survey Group) o strings PROJ. Por ejemplo, EPSG:4326 es el sistema de coordenadas geográficas WGS84, comúnmente usado para latitud/longitud. EPSG:3857 es el CRS de Web Mercator, popular en mapas web.

🔥 Importante: Trabajar con datos que tienen CRS diferentes puede llevar a errores o visualizaciones incorrectas. Siempre asegúrate de que tus capas espaciales estén en el mismo CRS si vas a realizar operaciones entre ellas.

🚀 Primeros Pasos: Cargando y Explorando Datos Geográficos

Para este tutorial, utilizaremos datos geográficos comunes disponibles públicamente. Un buen punto de partida son los datos de los países del mundo. Puedes descargar un shapefile (.shp) o un archivo GeoJSON de fuentes como Natural Earth Data.

💾 Descargando Datos de Ejemplo

Para facilitar el ejemplo, usaremos el conjunto de datos de países de GeoPandas mismo, que se descarga automáticamente la primera vez que se accede.

import geopandas as gpd
import matplotlib.pyplot as plt

# Cargar el conjunto de datos de países de ejemplo de GeoPandas
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))

# Mostrar las primeras filas del GeoDataFrame
print(world.head())

# Mostrar información general del GeoDataFrame
print(world.info())

# Obtener el CRS del GeoDataFrame
print(f"CRS actual: {world.crs}")

# Plotear el mundo básico
world.plot(figsize=(10, 6))
plt.title('Mapa Básico del Mundo')
plt.xlabel('Longitud')
plt.ylabel('Latitud')
plt.show()

Este código carga los datos de países, muestra las primeras filas para que veas su estructura, su CRS y luego los plotea. Notarás que la columna geometry es el corazón de tu GeoDataFrame.

ColumnaDescripción
------
pop_estPoblación estimada
continentContinente al que pertenece el país
------
nameNombre del país
iso_a3Código ISO A3 del país
------
gdp_md_estPIB estimado en millones de USD
geometryObjeto geométrico (generalmente un MultiPolygon)

🔍 Inspeccionando las Geometrías

Puedes acceder a las geometrías de un país específico. Por ejemplo, veamos la geometría de España:

espana = world[world['name'] == 'Spain']
print(type(espana.geometry.iloc[0]))
print(espana.geometry.iloc[0])

Esto te mostrará que la geometría de España es un MultiPolygon y te imprimirá sus coordenadas. Los objetos Shapely tienen métodos y atributos útiles para interactuar con ellos, como area, length, bounds, etc.

📊 Manipulación de Datos Geográficos

GeoPandas sobresale en la manipulación de datos espaciales. Aquí exploraremos algunas operaciones comunes.

🌍 Filtrado y Selección Espacial

Al igual que en Pandas, puedes filtrar filas basándote en valores de columna. Para el filtrado espacial, usamos métodos de GeoPandas.

Por ejemplo, seleccionemos solo los países de Europa:

euro_countries = world[world['continent'] == 'Europe']
euro_countries.plot(figsize=(10, 6), color='lightgreen', edgecolor='black')
plt.title('Países de Europa')
plt.show()

🔄 Reproyectar CRS

Es común trabajar con diferentes CRS. Para asegurar la compatibilidad y realizar mediciones precisas (áreas, distancias) en unidades métricas, a menudo necesitamos reproyectar nuestros datos a un CRS proyectado. El CRS original de naturalearth_lowres es EPSG:4326 (WGS84, lat/lon), que usa grados.

Para calcular áreas en kilómetros cuadrados, por ejemplo, necesitamos un CRS proyectado. Usaremos un CRS universal como EPSG:3857 (Web Mercator) para nuestro ejemplo.

# Reproyectar a Web Mercator (EPSG:3857)
world_projected = world.to_crs(epsg=3857)

# Comparar los CRS
print(f"CRS original: {world.crs}")
print(f"CRS proyectado: {world_projected.crs}")

# Calcular el área en kilómetros cuadrados (aproximado en Web Mercator)
world_projected['area_sqkm'] = world_projected.geometry.area / 10**6 # Convertir m^2 a km^2

print(world_projected[['name', 'area_sqkm']].sort_values(by='area_sqkm', ascending=False).head())
📌 Nota: Calcular áreas y distancias con `EPSG:3857` es una aproximación, especialmente en las regiones polares. Para cálculos de alta precisión, se recomienda usar CRS proyectados específicos para la región de interés.

🧩 Uniones Espaciales (sjoin)

Una de las características más potentes de GeoPandas es la capacidad de realizar uniones espaciales. Esto es similar a un merge de Pandas, pero en lugar de unir por un valor de columna, lo hace basándose en la relación espacial entre las geometrías.

Los tipos de uniones espaciales incluyen:

  • intersects: Si las geometrías se cruzan.
  • within: Si una geometría está completamente dentro de otra.
  • contains: Si una geometría contiene completamente a otra.

Imaginemos que tenemos un GeoDataFrame de ciudades y otro de países, y queremos saber a qué país pertenece cada ciudad. Esto sería una unión espacial within.

Para este ejemplo, crearemos un GeoDataFrame simple de puntos aleatorios para simular ciudades en Europa y los uniremos espacialmente con los países europeos.

from shapely.geometry import Point
import numpy as np

# Crear puntos aleatorios (simulando ciudades) dentro de un rango para Europa
np.random.seed(42)
cities_data = {
    'name': [f'Ciudad_{i}' for i in range(10)],
    'latitude': np.random.uniform(35, 70, 10),
    'longitude': np.random.uniform(-10, 30, 10)
}
cities_gdf = gpd.GeoDataFrame(
    cities_data,
    geometry=gpd.points_from_xy(cities_data['longitude'], cities_data['latitude']),
    crs="EPSG:4326" # Asegúrate de que el CRS sea el mismo que el de los países
)

# Cargar países europeos (asegurándonos de que esté en EPSG:4326)
euro_countries_4326 = world[world['continent'] == 'Europe'].to_crs(epsg=4326)

# Realizar la unión espacial (sjoin)
cities_with_country = gpd.sjoin(cities_gdf, euro_countries_4326, how="inner", predicate="within")

print(cities_with_country[['name_left', 'name_right', 'geometry']].head())

# name_left es el nombre de la ciudad, name_right es el nombre del país

# Visualizar la unión espacial
fig, ax = plt.subplots(1, 1, figsize=(12, 8))
euro_countries_4326.plot(ax=ax, color='lightgray', edgecolor='black')
cities_with_country.plot(ax=ax, marker='o', color='red', markersize=50, label='Ciudades en Países')
plt.title('Ciudades unidas espacialmente a países europeos')
plt.legend()
plt.show()

📈 Agregación Geoespacial

Puedes realizar agregaciones espaciales para resumir datos. Por ejemplo, podríamos calcular la población total por continente.

# Agrupar por continente y sumar la población estimada
pop_by_continent = world.groupby('continent')['pop_est'].sum().sort_values(ascending=False)
print(pop_by_continent)

# Unir estos datos de población de nuevo al GeoDataFrame de continentes (si tuviéramos uno)
# O simplemente usarlo para colorear un mapa temático.

🎨 Creando Mapas Temáticos Atractivos

La visualización es clave en el análisis geoespacial. GeoPandas se integra perfectamente con Matplotlib para crear mapas temáticos.

Mapa Coroplético Básico 📊

Un mapa coroplético colorea las regiones basándose en el valor de una variable. Crearemos un mapa que muestre la población estimada de los países.

fig, ax = plt.subplots(1, 1, figsize=(15, 10))

world.plot(
    column='pop_est', # Columna para colorear
    cmap='viridis',    # Mapa de colores
    linewidth=0.8,     # Grosor de la línea del borde
    ax=ax,             # Objeto Axes de Matplotlib
    edgecolor='0.8',   # Color del borde
    legend=True,       # Mostrar leyenda de colores
    legend_kwds={'label': "Población Estimada", 'orientation': "horizontal"}
)

ax.set_title('Población Estimada por País (2020)', fontsize=15)
ax.set_axis_off() # Ocultar ejes
plt.show()
Población Mundial Estimada Distribución regional por densidad demográfica Baja Población Alta Población

📍 Añadiendo Puntos a un Mapa

Podemos superponer diferentes tipos de geometrías. Por ejemplo, si tenemos un GeoDataFrame de capitales mundiales, podemos añadirlas a nuestro mapa de países.

# Datos de capitales (ejemplo simplificado)
capital_data = {
    'name': ['Madrid', 'Paris', 'Berlin', 'London'],
    'latitude': [40.4168, 48.8566, 52.5200, 51.5074],
    'longitude': [-3.7038, 2.3522, 13.4050, -0.1278]
}
capital_gdf = gpd.GeoDataFrame(
    capital_data,
    geometry=gpd.points_from_xy(capital_data['longitude'], capital_data['latitude']),
    crs="EPSG:4326"
)

fig, ax = plt.subplots(1, 1, figsize=(15, 10))

# Plotear los países (solo Europa para mayor claridad)
euro_countries_4326.plot(ax=ax, color='lightgray', edgecolor='black')

# Plotear las capitales
capital_gdf.plot(ax=ax, marker='*', color='red', markersize=200, label='Capitales', edgecolor='black')

# Añadir etiquetas a las capitales
for x, y, label in zip(capital_gdf.geometry.x, capital_gdf.geometry.y, capital_gdf['name']):
    ax.annotate(label, xy=(x, y), xytext=(3, 3), textcoords="offset points", fontsize=9)

ax.set_title('Capitales Europeas', fontsize=15)
ax.set_axis_off()
plt.legend()
plt.show()

Combinando múltiples capas y estilos avanzados

Para mapas más complejos, puedes combinar varias capas (GeoDataFrames) en el mismo Axes de Matplotlib, aplicando diferentes estilos y transparencias.

# Ejemplo: Mapa de Europa con países por PIB y capitales
fig, ax = plt.subplots(1, 1, figsize=(15, 10))

# 1. Capa de países europeos coloreados por PIB (normalizado para mejor visualización)
euro_countries_4326['gdp_normalized'] = np.log1p(euro_countries_4326['gdp_md_est']) # Usar log para suavizar grandes diferencias
euro_countries_4326.plot(
    column='gdp_normalized',
    cmap='YlGnBu', # Otro mapa de colores
    linewidth=0.8,
    ax=ax,
    edgecolor='0.8',
    legend=True,
    legend_kwds={'label': "PIB Estimado (logarítmico)", 'orientation': "horizontal"}
)

# 2. Capa de capitales
capital_gdf.plot(ax=ax, marker='o', color='purple', markersize=100, label='Capitales', edgecolor='white', alpha=0.7)

# Añadir etiquetas de las capitales
for x, y, label in zip(capital_gdf.geometry.x, capital_gdf.geometry.y, capital_gdf['name']):
    ax.annotate(label, xy=(x, y), xytext=(5, 5), textcoords="offset points", fontsize=8, color='black')

ax.set_title('PIB Estimado y Capitales en Europa', fontsize=16)
ax.set_axis_off()
plt.legend()
plt.show()
📌 Nota: Para mapas interactivos, puedes explorar librerías como `Folium` o `Plotly Express` que pueden integrar objetos GeoPandas para visualizaciones web. GeoPandas se enfoca más en el análisis y la visualización estática.

✨ Operaciones Geométricas Avanzadas

GeoPandas, al basarse en Shapely, permite realizar una amplia gama de operaciones geométricas.

📏 Búfer (buffer)

Crear un búfer alrededor de una geometría genera una nueva geometría que representa un área a una distancia específica de la original. Esto es útil para zonas de influencia.

# Crear un búfer de 2 grados alrededor de Madrid (CRS 4326 usa grados)
madrid_point = capital_gdf[capital_gdf['name'] == 'Madrid'].geometry.iloc[0]
madrid_buffer = madrid_point.buffer(2) # 2 grados de latitud/longitud

# Para un búfer en unidades métricas, primero reproyecta a un CRS proyectado
madrid_point_proj = capital_gdf[capital_gdf['name'] == 'Madrid'].to_crs(epsg=3857).geometry.iloc[0]
madrid_buffer_km = madrid_point_proj.buffer(200_000) # 200 km en metros

# Visualizar el búfer (reproyectar el buffer de vuelta a 4326 para plotear con el mapa mundial)
madrid_buffer_km_4326 = gpd.GeoSeries([madrid_buffer_km], crs='EPSG:3857').to_crs(epsg=4326)

fig, ax = plt.subplots(1, 1, figsize=(10, 8))
world[world['name'].isin(['Spain', 'France', 'Portugal'])].plot(ax=ax, color='lightgray', edgecolor='black')
gpd.GeoSeries([madrid_point], crs='EPSG:4326').plot(ax=ax, color='red', marker='*', markersize=200, label='Madrid')
madrid_buffer_km_4326.plot(ax=ax, color='blue', alpha=0.3, label='Búfer de 200km')

ax.set_title('Búfer de 200km alrededor de Madrid')
ax.set_axis_off()
plt.legend()
plt.show()

🤝 Uniones Geométricas (union)

Combina dos o más geometrías en una sola. Útil para fusionar países adyacentes o crear regiones. Por ejemplo, podemos unir Portugal y España para formar la península ibérica.

iberian_peninsula = euro_countries_4326[euro_countries_4326['name'].isin(['Spain', 'Portugal'])]

# Unir las geometrías de España y Portugal
united_iberia = iberian_peninsula.unary_union # O .union_all()

fig, ax = plt.subplots(1, 1, figsize=(8, 8))

# Plotear la península ibérica unida
gpd.GeoSeries([united_iberia], crs='EPSG:4326').plot(ax=ax, color='orange', edgecolor='black')

ax.set_title('Península Ibérica Unida')
ax.set_axis_off()
plt.show()
80% completado

💡 Consejos y Buenas Prácticas

  • Consistencia de CRS: Siempre verifica y, si es necesario, reproyecta tus datos a un CRS consistente antes de realizar operaciones espaciales entre ellos. ¡Es la causa más común de errores!
  • Rendimiento: Para grandes conjuntos de datos, las operaciones espaciales pueden ser costosas. Considera usar índices espaciales (rtree) o simplificar geometrías si la precisión extrema no es necesaria (simplify()).
  • Fuentes de Datos: Explora otras fuentes de datos geoespaciales como OpenStreetMap (vía osmnx), datos del INE, shapefiles gubernamentales, etc.
  • Visualización Interactiva: Para mapas web o interactivos, considera Folium, Plotly Express o hvPlot que se integran bien con GeoPandas.

❓ Preguntas Frecuentes (FAQ)

¿Qué diferencia hay entre GeoPandas y otras librerías SIG como QGIS o ArcGIS? GeoPandas es una librería de Python para programación y análisis geoespacial, ideal para automatización y análisis complejos dentro de un script. QGIS y ArcGIS son aplicaciones de escritorio SIG con interfaces gráficas completas, excelentes para edición, visualización interactiva y tareas de mapeo general. GeoPandas complementa estas herramientas, permitiendo a los usuarios de Python extender sus capacidades.
¿Puedo leer otros formatos de archivos además de Shapefiles y GeoJSON? Sí, GeoPandas (a través de Fiona) puede leer una amplia variedad de formatos vectoriales geoespaciales como KML, GPX, ESRI File Geodatabase, PostGIS, etc. Solo necesitas especificar la ruta al archivo. Si el formato no se carga directamente, asegúrate de tener las dependencias de GDAL/OGR necesarias instaladas.
¿Cómo manejo geometrías inválidas? Las geometrías inválidas (por ejemplo, polígonos que se auto-interceptan) pueden causar problemas en operaciones espaciales. Shapely tiene un método `.is_valid` para comprobar la validez y `.buffer(0)` o `.make_valid()` (disponible en versiones recientes de Shapely) para intentar reparar geometrías inválidas.

🎯 Conclusión

GeoPandas es una herramienta increíblemente poderosa para cualquier persona que necesite trabajar con datos geoespaciales en Python. Desde la carga y manipulación básica hasta la creación de mapas temáticos sofisticados y la realización de análisis espaciales complejos, ofrece una suite completa de funcionalidades. Dominar GeoPandas abre un mundo de posibilidades para entender y visualizar la información en su contexto geográfico, permitiéndote tomar decisiones más informadas y comunicar tus hallazgos de manera efectiva.

¡Anímate a explorar tus propios conjuntos de datos y a descubrir las historias que el espacio tiene para contar!

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!