es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Centroides de países en cartopy

Me gustaría usar centros de etiquetas significativos de alguna manera para etiquetas, etc. Aquí está mi código hasta ahora:

import cartopy.crs as ccrs
from cartopy.io import shapereader as shpreader
import matplotlib.pyplot as plt

geo_axes = plt.axes((2, 2, 2, 2), projection=ccrs.PlateCarree(central_longitude=0.0, globe=None))
geo_axes.set_global()

file = shpreader.natural_earth(resolution='10m', category='cultural', name='admin_0_countries')
all_countries = list(shpreader.Reader(file).records())

country_centroids = {country.attributes['SU_A3']: (country.geometry.centroid.y, country.geometry.centroid.x) for country in all_countries if country.attributes['SU_A3']}
for label in {'DEU', 'FRA', 'USA'}:
    geo_axes.plot(country_centroids[label][1], country_centroids[label][0], marker='x', color='red')

geo_axes.add_geometries([country.geometry for country in countries if country.attributes['SU_A3'] in {'DEU', 'FRA', 'USA'}], ccrs.PlateCarree(), facecolor='yellow', edgecolor='black', zorder=0)
geo_axes.add_geometries([country.geometry for country in countries if country.attributes['SU_A3'] not in {'DEU', 'FRA', 'USA'}], ccrs.PlateCarree(), facecolor='0.9', edgecolor='black', zorder=0)

Para Alemania, por ejemplo, es sencillo (sin regiones de ultramar, etc.) y funciona. Sin embargo, para Estados Unidos, por ejemplo, ya es incorrecto y, para Francia, es muy engañoso (es decir, el centro de Francia está en España).

¿Cómo puedo solucionarlo?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Una posible solución podría ser utilizar un enfoque diferente para determinar el centro de un país. En lugar de tomar el centroide de la geometría del país, que puede no ser siempre una representación significativa de su centro, podríamos utilizar una combinación de varios puntos que sean representativos de la forma y ubicación del país. Un enfoque como este es el uso del “centroide ponderado”, que tiene en cuenta el área y la ubicación de cada punto en la geometría del país. Aquí hay un ejemplo de código que muestra cómo calcular el centroide ponderado para cada país:

    from shapely.geometry import Polygon
    
    # Calcular el centroide ponderado para cada país
    centroides_pais = {}
    for pais in todos_los_paises:
        geometria = pais.geometria
        if pais.atributos['SU_A3']:
            if isinstance(geometria, Polygon):
                puntos = geometria.exterior.coords[:-1]
                area = geometria.area
            else:
                puntos = []
                area = 0.0
                for poligono in geometria:
                    puntos += poligono.exterior.coords[:-1]
                    area += poligono.area
            # Cálculo del centroide ponderado
            x = sum([p[0] * p[1] for p in puntos]) / (6 * area)
            y = sum([p[1] * p[0] for p in puntos]) / (6 * area)
            centroides_pais[pais.atributos['SU_A3']] = (y, x)
    

    Este código primero verifica si la geometría de cada país es un Polígono (es decir, una forma contigua única) o una colección de Polígonos (por ejemplo, un país con islas o exclaves). Luego, extrae las coordenadas exteriores de cada forma y calcula el área total de la geometría del país. Utilizando estos valores, aplica la fórmula del centroide ponderado:

    fórmula del centroide ponderado

    donde x e y son las coordenadas de cada punto, w es un peso proporcional al área del triángulo formado por ese punto y sus puntos vecinos, y las sumas se toman sobre todos los puntos. Ten en cuenta que la fórmula asume un orden de puntos en sentido horario, que es la convención utilizada por Cartopy y Shapely.

    Con estos nuevos centroides, podemos actualizar el código de trazado de la siguiente manera:

    for etiqueta in {'DEU', 'FRA', 'USA'}:
        geo_ejes.plot(centroides_pais[etiqueta][1], centroides_pais[etiqueta][0], marcador='x', color='rojo')
    
    geo_ejes.add_geometries([pais.geometria for pais in paises if pais.atributos['SU_A3'] in {'DEU', 'FRA', 'USA'}], ccrs.PlateCarree(), facecolor='amarillo', edgecolor='negro', zorder=0)
    geo_ejes.add_geometries([pais.geometria for pais in paises if pais.atributos['SU_A3'] not in {'DEU', 'FRA', 'USA'}], ccrs.PlateCarree(), facecolor='0.9', edgecolor='negro', zorder=0)
    

    Esto debería producir un mapa con centros de país más precisos:

    mapa con centroides ponderados

Comments are closed.