Python está dotado de múltiples librerías enfocadas al mundo Geo, no sólo para análisis geoespacial, sino también para la visualización de información espacial en forma de gráficos y, como no, de mapas.
Matplotlib es una de las principales librerías para visualización y análisis de datos de cualquier tipo, también espaciales.
A pesar de su sencillez, puede resultar en ocasiones ciertamente tediosa la tarea de configurar las vistas de mapa. El juego que ofrece es más bien escaso.
Como vimos en otro post, podemos realizar visualizaciones en forma de mapas simples con Matplotlib y Geopandas.
De hecho, si bien Matplotlib permite realizar mapas con éxito, el objetivo claro y central de esta librería es plotear gráficos. En cualquier caso, esta opción se encuentra bastante limitada y no permite customizar las visualizaciones de manera intuitiva y ágil.
No obstante, existen otras opciones.
La librería Basemap para producir mapas con Python
Basemap no es exactamente una librería como tal. De hecho, es un conjunto de herramientas, una extensión, de la propia librería Matplotlib de Python.
Con este conjunto de herramientas podremos representar información geográfica vectorial y ráster sobre gráficos 2D. Funciona sobre diversas librerías además de Matplotlib como Proj4, Generic Mapping Tools y GEOS.
De hecho, Basemap facilita la conversión a múltiples proyecciones cartográficas, el uso de cartografía base como referencia espacial sin tener que cargarla manualmente de fuentes externas y permite realizar composiciones y visualizaciones algo más avanzadas.
En este breve artículo, a modo de tutorial, veremos distintos ejemplos jugando con un dataset bastante reducido y sencillo múltiples maneras de visualizar mapas personalizados.
La ejecución del código y la visualización de mapas se hará sobre Jupyter Notebook.
Generando un mapa simple en Python con Basemap
Lo primero que deberemos hacer desde Jupyter Notebook será importar las librerías y los paquetes implicados:
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from mpl_toolkits.basemap import Basemap
A continuación estableceremos las rutas a los archivos que utilizaremos. Se tratan, como ejemplo, datos referentes a las trayectorias de distintos huracanes en el área del Atlántico y el Caribe durante la temporada 2018.
# Establecer archivos de cada una de las trayectorias
h1 = "huracanes/AL012018_lin"
h2 = "huracanes/AL022018_lin"
h3 = "huracanes/AL032018_lin"
h4 = "huracanes/AL042018_lin"
h5 = "huracanes/AL072018_lin"
En esta primera visualización tan sólo utilizaremos el primer archivo, un shapefile con una única trayectoria, correspondiente a una geometría de tipo línea.
Para crear este primer mapa de visualización deberemos realizar una serie de acciones:
# Habilitamos la figura y establecemos ejes y título
fig = plt.figure(figsize=(15, 10))
ax = fig.add_subplot(1,1,1)
ax.set_title('Trayectoria del Huracan 1')
# Establecemos la proyección del mapa base
m = Basemap(
ax = ax,
resolution = 'l',
projection = 'merc',
llcrnrlon = -140, llcrnrlat = 10,
urcrnrlon = -20, urcrnrlat = 50
)
# Establecemos las capas vectoriales a cargar como mapa base
countries = m.drawcountries(color='#303338')
mares = m.drawmapboundary(fill_color='#c0eaff')
costa = m.drawcoastlines(color='#324c87')
tierra = m.fillcontinents(color='#ebe7d5', lake_color='#c0eaff')
# Añadimos las capas vectoriales con información temática
map_trayectoria = m.readshapefile(h1, 'Huracan 1', color='#ff5d17', linewidth=2)
El resultado ofrecido es el siguiente:
Visualizando múltiples vistas de mapa o subplots con Basemap
Otra de las opciones que permite Basemap junto a Matplotlib es la visualización en paralelo de múltiples vistas de mapa.
Para ello, deberán establecerse subplots o áreas de gráfico dedicadas a cada una de las figuras que se desean visualizar. Cabe destacar que deberemos establecer una correcta adjudicación del espacio (posición) del gráfico.
Esto lo haremos, como veremos a continuación, dotando a cada subplot de unas «coordenadas» del estilo: (2, 2, 1), siendo igualmente válido asignar (221) alternativamente.
# Establecer tamaño del entorno de las figuras
fig = plt.figure(figsize=(15, 10))
# Mapa 1
ax = fig.add_subplot(2,2,1)
ax.set_title('Huracan 1')
m = Basemap(
ax = ax,
resolution = 'l',
projection = 'merc',
llcrnrlon = -120, llcrnrlat = 0,
urcrnrlon = 20, urcrnrlat = 65
)
mares = m.drawmapboundary(fill_color='#c0eaff')
costa = m.drawcoastlines(color='#706c58')
tierra = m.fillcontinents(color='#ebe7d5', lake_color='#c0eaff')
map_tray1 = m.readshapefile(h1, 'Huracan 1', color='#ff5d17', linewidth=2)
# Mapa 2
ax = fig.add_subplot(2,2,2)
ax.set_title('Huracan 2')
m = Basemap(
ax = ax,
resolution = 'l',
projection = 'merc',
llcrnrlon = -120, llcrnrlat = 0,
urcrnrlon = 20, urcrnrlat = 65
)
mares = m.drawmapboundary(fill_color='#c0eaff')
costa = m.drawcoastlines(color='#706c58')
tierra = m.fillcontinents(color='#ebe7d5', lake_color='#c0eaff')
map_tray2 = m.readshapefile(h2, 'Huracan 2', color='#ffe312', linewidth=2)
# Mapa 3
ax = fig.add_subplot(2,2,3)
ax.set_title('Huracan 3')
m = Basemap(
ax = ax,
resolution = 'l',
projection = 'merc',
llcrnrlon = -120, llcrnrlat = 0,
urcrnrlon = 20, urcrnrlat = 65
)
mares = m.drawmapboundary(fill_color='#c0eaff')
costa = m.drawcoastlines(color='#706c58')
tierra = m.fillcontinents(color='#ebe7d5', lake_color='#c0eaff')
map_tray3 = m.readshapefile(h3, 'Huracan 3', color='#30a64d', linewidth=2)
# Mapa 4
ax = fig.add_subplot(2,2,4)
ax.set_title('Huracan 4')
m = Basemap(
ax = ax,
resolution = 'l',
projection = 'merc',
llcrnrlon = -120, llcrnrlat = 0,
urcrnrlon = 20, urcrnrlat = 65
)
mares = m.drawmapboundary(fill_color='#c0eaff')
costa = m.drawcoastlines(color='#706c58')
tierra = m.fillcontinents(color='#ebe7d5', lake_color='#c0eaff')
map_tray4 = m.readshapefile(h4, 'Huracan 4', color='#e02d5a', linewidth=2)
# Mostramos el gráfico con los múltiples mapas
plt.show()
Como resultado se obtiene la siguiente figura compuesta por 4 subplots o vistas de mapa en paralelo:
Creando una visualización algo más avanzada
Ahora trataremos de mostrar todas las trayectorias en una única vista algo más avanzada en cuanto a personalización.
Trataremos de añadir una leyenda, personalizar el mapa base con una capa ráster de relieve ofrecida por Basemap y añadir unos créditos a la figura:
fig, ax = plt.subplots(figsize=(10, 10))
m = Basemap(
ax = ax,
resolution = 'l',
projection = 'ortho',
lon_0 = -40, lat_0 = 35
# llcrnrlon = -12, llcrnrlat = 28,
# urcrnrlon = 45, urcrnrlat = 50
)
# Cargar cartografía ráster base
tierra = m.shadedrelief()
# Mostrar paralelos y meridianos
import numpy as np
paralelos = m.drawparallels(np.linspace(-90,90,13), color='grey')
meridianos = m.drawmeridians(np.linspace(-180,180,13), color='grey')
# Cargar y mostrar las trayectorias diferenciadas por color
map_tray1 = m.readshapefile(h1, 'Huracan 1', color='#ff5d17', linewidth=2)
map_tray2 = m.readshapefile(h2, 'Huracan 2', color='#ffe312', linewidth=2)
map_tray3 = m.readshapefile(h3, 'Huracan 3', color='#30a64d', linewidth=2)
map_tray4 = m.readshapefile(h4, 'Huracan 4', color='#e02d5a', linewidth=2)
map_tray5 = m.readshapefile(h5, 'Huracan 5', color='#8d20d6', linewidth=2)
# Añadir un título
plt.title('Huracanes en 2018', fontdict={'fontsize':22}, pad=20)
# Añadir una leyenda
elem_leyenda = [
Line2D([0], [0], label='Huracan 1', color='#ff5d17', linewidth=2),
Line2D([0], [0], label='Huracan 2', color='#ffe312', linewidth=2),
Line2D([0], [0], label='Huracan 3', color='#30a64d', linewidth=2),
Line2D([0], [0], label='Huracan 4', color='#e02d5a', linewidth=2),
Line2D([0], [0], label='Huracan 5', color='#8d20d6', linewidth=2)
]
ax.legend(handles=elem_leyenda, title='Trayectorias', title_fontsize=15,
fontsize=12, loc='upper right', facecolor='white', shadow=True,
borderpad=2, columnspacing=2, labelspacing=1)
plt.xlabel("Datos de NOAA - NHC (National Hurricane Center)",
fontsize=12, labelpad=30)
plt.show()
Como resultado del anterior bloque de código Python obtenemos la siguiente figura:
Como vemos las opciones de personalización de estos gráficos son ciertamente algo más avanzadas que con Matplotlib de base, orientándose específicamente a la visualización de información geográfica.
No obstante, existen otras opciones para generar mapas de forma automatizada mediante Python que permiten obtener resultados de una manera más ágil e incluso dotarlos de interactividad.
Es el caso de librerías como Plotly para Python, ejecutables también desde Jupyter Notebook.
Puedes encontrar más información en nuestro artículo en el que se muestra cómo realizar gráficos y mapas interactivos con Plotly.
Hola, excelente aporte. Muchas gracias. Lo utilizaré en su momento