Cómo visualizar el contorno de un país en Jupyter usando GeoPandas, Cartopy y Natural Earth

Este sencillo ejemplo muestra cómo visualizar el contorno de un país en Jupyter. Para este ejemplo, mostraremos el contorno de Alemania. Para hacerlo visualmente más atractivo, también añadimos los contornos de otros países y el océano en el fondo.

Usamos el conjunto de datos Natural Earth 10m, que se descarga automáticamente aquí. Las variantes a mayor escala como 1:110M simplemente no proporcionan suficiente resolución a esta escala para ser visualmente atractivas.

Germany with rivers.avif

VisualizeCountry.py
# Importar las bibliotecas necesarias
import cartopy.crs as ccrs
import cartopy.feature as cf
from cartopy.feature import ShapelyFeature
import cartopy.io.shapereader as shpreader
import matplotlib.pyplot as plt
import geopandas as gpd
from shapely.ops import unary_union

# Crear el mapa con la proyección Plate Carree
proj = ccrs.PlateCarree()
ax = plt.axes(projection=proj)
# Obtendremos Natural Earth de mayor resolución (10m) cuando esté disponible
# Usar 'admin_0_countries' de 10m y costa/lagos/ríos para mayor detalle
try:
    # Leer los países de Natural Earth 10m y extraer la geometría de Alemania vía geopandas para mayor precisión
    countries = gpd.read_file(shpreader.natural_earth(resolution='10m', category='cultural', name='admin_0_countries'))
    germany = countries[countries['ISO_A3'] == 'DEU'].iloc[0].geometry
    # Aplicar un buffer de 0 para corregir cualquier geometría inválida
    germany = germany.buffer(0)
    # Determinar una extensión ajustada a partir de la geometría con un pequeño relleno en grados
    minx, miny, maxx, maxy = germany.bounds
    pad_deg = 0.4
    extent = [minx - pad_deg, maxx + pad_deg, miny - pad_deg, maxy + pad_deg]
    ax.set_extent(extent, crs=ccrs.PlateCarree())

    # Añadir costa, fronteras, lagos y ríos de alta resolución
    # NOTA: Todos estos son opcionales - simplemente comenta lo que no necesites
    ax.add_feature(cf.LAND.with_scale('10m'), facecolor='lightgray')
    ax.add_feature(cf.OCEAN.with_scale('10m'), facecolor='lightblue')
    ax.add_feature(cf.COASTLINE.with_scale('10m'), lw=0.6)
    ax.add_feature(cf.BORDERS.with_scale('10m'), linestyle=':', lw=0.6)
    ax.add_feature(cf.LAKES.with_scale('10m'), facecolor='none', edgecolor='blue', lw=0.4)
    ax.add_feature(cf.RIVERS.with_scale('10m'), edgecolor='blue', lw=0.4)

    # Añadir el polígono de Alemania con un estilo más atractivo
    germany_feature = ShapelyFeature([germany], ccrs.PlateCarree(), facecolor='none', edgecolor='red', linewidth=1.2)
    ax.add_feature(germany_feature)

    # Añadir líneas de cuadrícula y título
    gl = ax.gridlines(draw_labels=True, linestyle='--', linewidth=0.3)
    gl.top_labels = False
    gl.right_labels = False
    plt.gcf().set_size_inches(12, 10)
    ax.set_title('Outline of Germany — Natural Earth 10m (detailed)')

    plt.show()
except Exception as e:
    print(f"Error: {e}")
    print("Could not load 10m Natural Earth data. Falling back to built-in shapereader records with 110m resolution.")
    try:
        reader = shpreader.Reader(shpreader.natural_earth(resolution='110m', category='cultural', name='admin_0_countries'))
        germany = [c for c in reader.records() if c.attributes['NAME_LONG'] == 'Germany'][0]
        shape_feature = ShapelyFeature([germany.geometry], ccrs.PlateCarree(), facecolor='none', edgecolor='red', lw=2)
        ax.add_feature(cf.COASTLINE, lw=0.5)
        ax.add_feature(cf.BORDERS, linestyle=':', lw=0.5)
        ax.add_feature(shape_feature)
        plt.show()
    except Exception as e2:
        print('Fallback also failed:', e2)

Echa un vistazo a artículos similares por categoría: Geoinformatics