Search code examples
pythonmatplotlibcartopy

Plotting text in Cartopy just inside my figure


I'm trying to plot some big cities of Spain and tag them with their names, according to Natural Earth data. If I only plot the points, using ax.scatter, I get my figure correctly, without points outside it. But when doing ax.text in the same way, I get all the names of cities of the world outside the picture...

The code is here:

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

# Downloaded from https://gadm.org/download_country_v3.html. Those are the borders
fname = 'C:/Users/lordf/Downloads/gadm36_ESP_shp/gadm36_ESP_2.shp'
adm1_shapes = list(shpreader.Reader(fname).geometries())

cname = shpreader.natural_earth(resolution='10m', category='cultural', name='populated_places')
reader = shpreader.Reader(cname) #data of cities

plt.figure(figsize=(10,10))

ax = plt.axes(projection=ccrs.PlateCarree())
ax.set_extent([-10, 1, 35, 45], ccrs.PlateCarree())
plt.title('Spain')
ax.coastlines(resolution='10m')

ax.add_geometries(adm1_shapes, ccrs.PlateCarree(),
                  edgecolor='black', facecolor='gray', alpha=0.5) #borders

points = list(reader.geometries())
cities = list(reader.records())

ax.scatter([point.x for point in points],
           [point.y for point in points],
           transform=ccrs.PlateCarree(),
           s=[10*np.exp(1/(city.attributes['SCALERANK']+1)) for city in cities], c='r')
          #trying to match the size of the point to the population

#This gives me error, dont know why:
# ax.text([point.x for point in points], [point.y for point in points], 
#         [city.attributes['NAME'] for city in cities], 
#         transform=ccrs.PlateCarree())

#This is what plots the text outside the figure:
for i in range(len(points)):
    ax.text(points[i].x, points[i].y, cities[i].attributes['NAME'], transform=ccrs.PlateCarree())

ax.set_extent([-10, 1, 35, 45], ccrs.PlateCarree())

plt.show()

This is part of the image output Thanks for any help.


Solution

  • You must select only points and cities of Kingdom of Spain before plotting. Here is the relevant code:

    spain_points = []
    spain_cities = []
    for city,xy in zip(cities, points):
        if city.attributes["SOV0NAME"]=="Kingdom of Spain":
            print(city.attributes["NAME"], xy)
            spain_points.append(xy)
            spain_cities.append(city)
            pass
        pass
    

    Then proceed with spain_points and spain_cities in places of points and cities in your code.