Search code examples
pythonmatplotlibcartopy

How to plot map with auto name annotation?


I tried to plot a map like this: map

It's easy to plot the background, is it possible to add the names automatically?

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import matplotlib.path as mpath
import numpy as np
ax = plt.subplot(projection=ccrs.NorthPolarStereo())
ax.set_extent([0, 360, 50, 90], crs=ccrs.PlateCarree())

ax.stock_img()
ax.coastlines()

# Compute a circle in axes coordinates, which we can use as a boundary
# for the map. We can pan/zoom as much as we like - the boundary will be
# permanently circular.
theta = np.linspace(0, 2*np.pi, 100)
center, radius = [0.5, 0.5], 0.5
verts = np.vstack([np.sin(theta), np.cos(theta)]).T
circle = mpath.Path(verts * radius + center)

ax.set_boundary(circle, transform=ax.transAxes)

map2


Solution

  • There is no automatic map annotation plotting with cartopy. But it is possible to do so with some programming and data. Proper locations and orientations of the anno-texts will be needed. Here is the code that demonstrates the process.

    import matplotlib.pyplot as plt
    import cartopy.crs as ccrs
    import matplotlib.path as mpath
    import numpy as np
    
    fig = plt.figure(figsize=[8, 8])
    ax = plt.subplot(projection=ccrs.NorthPolarStereo())
    #ax.set_extent([0, 360, 50, 90], crs=ccrs.PlateCarree())
    ax.set_extent([-180, 180, 50, 90], ccrs.PlateCarree())
    
    ax.stock_img()
    ax.coastlines()
    
    def map_annotation(lonlat_list, rotate_deg, anno_text):
        l2 = np.array(lonlat_list)
        # Rotate angle
        angle = rotate_deg
        trans_angle = plt.gca().transData.transform_angles(np.array((angle,)),
                                                           l2.reshape((1, 2)))[0]
        plt.text(l2[0], l2[1] , anno_text,
                 rotation=trans_angle, rotation_mode='anchor',
                 transform=ccrs.PlateCarree())
    
    # Annotate some areas/features for demonstratioin
    map_annotation((0, 60), 90, 'Prime  meridian')
    map_annotation((-42, 65.5), 45, '    Greenland')
    map_annotation((-102, 60), 45, 'C a n a d a')
    map_annotation((38, 55), 70, 'R   u   s   s   i   a')
    
    theta = np.linspace(0, 2*np.pi, 100)
    center, radius = [0.5, 0.5], 0.5
    verts = np.vstack([np.sin(theta), np.cos(theta)]).T
    circle = mpath.Path(verts * radius + center)
    
    ax.set_boundary(circle, transform=ax.transAxes)
    
    plt.show()
    

    The output:-

    annotextmap