Làm cách nào để đặt nhãn trên một quốc gia có bản đồ Python?


8

Sử dụng python3 và cartopy, có mã này:

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()

Tôi nhận được điều này:

nhập mô tả hình ảnh ở đây

Câu hỏi: Tôi nên viết gì, để có chữ " A " màu đỏ trên Bulgaria (hoặc bất kỳ quốc gia nào khác mà tôi đề cập đến country.attributes['SOVEREIGNT'])? Hiện tại nhãn không được hiển thị và tôi không chắc chắn làm thế nào để thay đổi phông chữ của nhãn. Vì vậy, dường như sau đây chỉ thay đổi màu sắc, mà không thêm nhãn:

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

Câu trả lời:


9

Bạn có thể truy xuất trọng tâm của hình học và vẽ văn bản tại vị trí đó:

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'])

Với mức độ tập trung vào "Bulgaria", có vẻ như:

nhập mô tả hình ảnh ở đây

biên tập:

Để tách riêng "phụ thuộc", hãy xem xét sử dụng admin_0_map_unitsthay vì admin_0_map_countries, xem tài liệu về Trái đất tự nhiên .

Để làm nổi bật các quốc gia / khu vực nhỏ, bạn có thể thêm bộ đệm vào hình học bằng một cái gì đó như:

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'])

nhập mô tả hình ảnh ở đây

Bạn có thể tách một quốc gia cụ thể bằng một cái gì đó như thế này, Nó sử dụng Shapely để thực hiện một giao lộ ở giữa hình học. Cuối cùng, có thể "sạch" hơn để phân tách âm mưu và phân tích không gian (tách v.v.) thành các bước khác biệt hơn. Trộn nó như thế này có lẽ làm cho việc sử dụng lại mã cho các trường hợp khác khó khăn hơn.

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'])

nhập mô tả hình ảnh ở đây


Chắc chắn là một câu trả lời tốt, cảm ơn bạn cho những nỗ lực! Và như một câu hỏi hoàn toàn không liên quan - nếu tôi muốn lập bản đồ Singapore hoặc Lichtenstein màu xanh lá cây, tôi phải làm gì?
Vityata

1
Tôi đã thực hiện một chỉnh sửa cho câu trả lời. Hình ảnh hiển thị đa giác với vùng đệm 2 độ nếu diện tích nhỏ hơn 2 độ vuông (không phải là đơn vị tốt nhất để ánh xạ). Tôi đã thêm một phần bù vào nhãn để tránh đặt quá nhiều quốc gia.
Rutger Kassies

Tôi quản lý để lọc các lãnh thổ phụ thuộc đi bằng cách kiểm tra country.attributes['NAME_EN'] == "France". Dù sao, liên quan đến "Singapore" và "Lichtenstein", tôi đoán tôi nên thử đưa ra tọa độ thủ công?
Vityata

1
Những quốc gia đó sẽ rất nhỏ trên một bản đồ lớn, nhưng tôi nghĩ bạn vẫn có thể sử dụng khái niệm tương tự để hoàn thành nó.
Rutger Kassies

1
Tôi nhận thấy nhận xét này trong các tài liệu: "Nếu bạn muốn thấy các khu vực phụ thuộc ở nước ngoài bị phá vỡ (như trong mã ISO, hãy xem Pháp chẳng hạn), thay vào đó hãy sử dụng các đơn vị bản đồ". và nghĩ rằng nó có thể phù hợp hơn trong trường hợp này. Đó là trong phần "giới thiệu" tại: Naturalearthdata.com/doads/10m-cestation-vector/
mẹo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.