Wie beschrifte ich ein Land mit Python-Karton?

8

Verwenden von Python3 und Cartopy mit folgendem Code:

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

ax = plt.axes(projection=ccrs.PlateCarree())
ax.add_feature(cartopy.feature.LAND)
ax.add_feature(cartopy.feature.OCEAN)
ax.add_feature(cartopy.feature.COASTLINE)
ax.add_feature(cartopy.feature.BORDERS, linestyle='-', alpha=.5)
ax.add_feature(cartopy.feature.LAKES, alpha=0.95)
ax.add_feature(cartopy.feature.RIVERS)

ax.set_extent([-150, 60, -25, 60])

shpfilename = shpreader.natural_earth(resolution='110m',
                                      category='cultural',
                                      name='admin_0_countries')

reader = shpreader.Reader(shpfilename)
countries = reader.records()

for country in countries:
    if country.attributes['SOVEREIGNT'] == "Bulgaria":
        ax.add_geometries(country.geometry, ccrs.PlateCarree(), facecolor=(0, 1, 0), label = "A")
    else:
        ax.add_geometries(country.geometry, ccrs.PlateCarree(), facecolor=(1, 1, 1), label = country.attributes['SOVEREIGNT'])
plt.rcParams["figure.figsize"] = (50,50)
plt.show()

Ich verstehe das:

Geben Sie hier die Bildbeschreibung ein

Frage: Was soll ich schreiben, um ein rotes " A " über Bulgarien (oder einem anderen Land, auf das ich mich beziehe country.attributes['SOVEREIGNT']) zu bekommen? Derzeit wird das Etikett überhaupt nicht angezeigt und ich bin nicht sicher, wie ich die Schriftart des Etiketts ändern soll. Es scheint also, dass das Folgende nur die Farbe ändert, ohne das Etikett hinzuzufügen:

ax.add_geometries(country.geometry, ccrs.PlateCarree(), facecolor=(0, 1, 0), label = "A")
Vityata
quelle

Antworten:

9

Sie können den Schwerpunkt der Geometrie abrufen und den Text an dieser Stelle zeichnen:

import matplotlib.patheffects as PathEffects

for country in countries:

    if country.attributes['SOVEREIGNT'] == "Bulgaria":
        g = ax.add_geometries(country.geometry, ccrs.PlateCarree(), facecolor=(0, 1, 0), label="A")

        x = country.geometry.centroid.x        
        y = country.geometry.centroid.y

        ax.text(x, y, 'A', color='red', size=15, ha='center', va='center', transform=ccrs.PlateCarree(), 
                path_effects=[PathEffects.withStroke(linewidth=5, foreground="k", alpha=.8)])

    else:
        ax.add_geometries(country.geometry, ccrs.PlateCarree(), facecolor=(1, 1, 1), label = country.attributes['SOVEREIGNT'])

Mit dem Ausmaß, das sich auf "Bulgarien" konzentriert, sieht es so aus:

Geben Sie hier die Bildbeschreibung ein

bearbeiten:

Um "Abhängigkeiten" zu trennen, sollten Sie die Option " admin_0_map_unitsstatt" verwenden admin_0_map_countries, siehe Dokumentation zur natürlichen Erde .

Um kleine Länder / Regionen hervorzuheben, können Sie der Geometrie einen Puffer hinzufügen, der Folgendes umfasst:

highlight = ['Singapore', 'Liechtenstein']

for country in countries:

    if country.attributes['NAME'] in highlight:

        if country.geometry.area < 2:
            geom = [country.geometry.buffer(2)]
        else:
            geom = [country.geometry]

        g = ax.add_geometries(geom, ccrs.PlateCarree(), facecolor=(0, 0.5, 0, 0.6), label="A", zorder=99)

        x = country.geometry.centroid.x        
        y = country.geometry.centroid.y

        ax.text(x, y+5, country.attributes['NAME'], color='red', size=14, ha='center', va='center', transform=ccrs.PlateCarree(), 
                path_effects=[PathEffects.withStroke(linewidth=3, foreground="k", alpha=.8)])

    else:
        ax.add_geometries(country.geometry, ccrs.PlateCarree(), facecolor=(1, 1, 1), label=country.attributes['NAME'])

Geben Sie hier die Bildbeschreibung ein

Sie können ein bestimmtes Land mit so etwas teilen. Es verwendet Shapely, um einen Schnittpunkt in der Mitte der Geometrie auszuführen. Letztendlich könnte es "sauberer" sein, die Darstellung und räumliche Analyse (Aufteilung usw.) in klarere Schritte zu unterteilen. Wenn Sie es so mischen, ist es wahrscheinlich schwieriger, den Code für andere Fälle wiederzuverwenden.

from shapely.geometry import LineString, MultiLineString

for country in countries:

    if country.attributes['NAME'] in 'China':

        # line at the centroid y-coord of the country
        l = LineString([(-180, country.geometry.centroid.y), 
                        (180, country.geometry.centroid.y)])

        north_poly = MultiLineString([l, north_line]).convex_hull
        south_poly = MultiLineString([l, south_line]).convex_hull

        g = ax.add_geometries([country.geometry.intersection(north_poly)], ccrs.PlateCarree(), facecolor=(0.8, 0.0, 0.0, 0.4), zorder=99)
        g = ax.add_geometries([country.geometry.intersection(south_poly)], ccrs.PlateCarree(), facecolor=(0.0, 0.0, 0.8, 0.4), zorder=99)

        x = country.geometry.centroid.x        
        y = country.geometry.centroid.y

        ax.text(x, y, country.attributes['NAME'], color='k', size=16, ha='center', va='center', transform=ccrs.PlateCarree(), 
                path_effects=[PathEffects.withStroke(linewidth=5, foreground="w", alpha=1)], zorder=100)

    else:
        ax.add_geometries(country.geometry, ccrs.PlateCarree(), facecolor=(1, 1, 1), label=country.attributes['NAME'])

Geben Sie hier die Bildbeschreibung ein

Rutger Kassies
quelle
Auf jeden Fall eine gute Antwort, danke für die Bemühungen! Und als völlig unabhängige Frage: Was soll ich tun, wenn ich Singapur oder Lichtenstein grün abbilden möchte?
Vityata
1
Ich habe die Antwort bearbeitet. Das Bild zeigt das Polygon mit einem Puffer von 2 Grad, wenn die Fläche weniger als 2 Quadratgrad beträgt (nicht die beste Einheit für die Abbildung). Ich habe dem Etikett einen Versatz hinzugefügt, um ein Überzeichnen des Landes selbst zu vermeiden.
Rutger Kassies
Ich habe es geschafft, die abhängigen Gebiete wegzufiltern, indem ich das überprüft habe country.attributes['NAME_EN'] == "France". Was "Singapur" und "Lichtenstein" betrifft, sollte ich versuchen, manuelle Koordinaten anzugeben?
Vityata
1
Diese Länder werden auf einer großen Karte sehr klein sein, aber ich denke, Sie könnten immer noch das gleiche Konzept verwenden, um dies zu erreichen.
Rutger Kassies
1
Ich bemerkte diese Bemerkung in den Dokumenten: "Wenn Sie die abhängigen überseeischen Regionen aufteilen möchten (wie in ISO-Codes, siehe beispielsweise Frankreich), verwenden Sie stattdessen Karteneinheiten." und dachte, es könnte in diesem Fall angemessener sein. Es ist im "Über" Teil unter: naturalearthdata.com/downloads/10m-cultural-vectors/…
Rutger Kassies