Javier
Javier

Reputation: 513

How to plot the name of the states in a cartopy map?

I have a shapefile with the information of the names of the states of Perú country, and I want to plot them on the map according to their state.

So i did this code:

import cartopy
%matplotlib inline
import cartopy.crs as ccrs
import cartopy.io.img_tiles as cimgt
import cartopy.io.shapereader as shpreader
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
from cartopy.feature import NaturalEarthFeature


reader = shpreader.Reader('C:/my/route/STATES_PERU.shp')
counties = list(reader.geometries())
states = reader.records()
state = next(states)

states_att = lambda state: state.attributes['DEPARTAMEN']
states_names = sorted(reader.records(), key=states_att)

COUNTIES = cfeature.ShapelyFeature(counties, ccrs.PlateCarree())
STATES = cfeature.ShapelyFeature(states_names, ccrs.PlateCarree())

fig = plt.figure('map', figsize=(7,7), dpi=200)
ax = fig.add_axes([0.1, 0.12, 0.80, 0.75], projection=ccrs.PlateCarree())

l1 = NaturalEarthFeature(category='cultural', name='admin_0_countries', scale='50m', facecolor='none')
ax.add_feature(l1, edgecolor='black', linewidth=0.1)

ax.set_extent([-83.0, -66.0, -19.0, 1.0], crs=ccrs.PlateCarree())

ax.add_feature(COUNTIES, facecolor='none', edgecolor='black')
ax.add_feature(STATES)

When i run this code i got this error:

AttributeError: 'FionaRecord' object has no attribute '_geom'

The variable COUNTIES have Polygon elements and the variable STATES have FionaRecord elements.

How can i plot the names of the states in the cartopy map, that are inside the variable STATES?

Thanks in advance.

Upvotes: 0

Views: 1232

Answers (1)

Rutger Kassies
Rutger Kassies

Reputation: 64443

It's probably easiest to loop over the records that the shpreader returns. That allows you to for example get the coordinates of the centroid of the polygon, and use that to plot the name from the attributes.

Using NE sample data:

import cartopy.crs as ccrs
import cartopy.io.shapereader as shpreader
import cartopy.feature as cfeature

import matplotlib.pyplot as plt
import matplotlib.patheffects as PathEffects

# get the data
fn = shpreader.natural_earth(
    resolution='10m', category='cultural', 
    name='admin_1_states_provinces',
)
reader = shpreader.Reader(fn)
states = [x for x in reader.records() if x.attributes["admin"] == "Peru"]
states_geom = cfeature.ShapelyFeature([x.geometry for x in states], ccrs.PlateCarree())

data_proj = ccrs.PlateCarree()

# create the plot
fig, ax = plt.subplots(
    figsize=(7,7), dpi=130, facecolor="w",
    subplot_kw=dict(projection=data_proj),
)

ax.add_feature(cfeature.BORDERS, color="k", lw=0.1)
ax.set_extent([-83.0, -66.0, -19.0, 1.0], crs=data_proj)

ax.add_feature(states_geom, facecolor="none", edgecolor="k")

# add the names
for state in states:
    
    lon = state.geometry.centroid.x
    lat = state.geometry.centroid.y
    name = state.attributes["name"] 
    
    ax.text(
        lon, lat, name, size=7, transform=data_proj, ha="center", va="center",
        path_effects=[PathEffects.withStroke(linewidth=5, foreground="w")]
    )                                  

This method probably will cause some overlap between the labels. I'm not sure if there are more advanced label placement algorithms available that work well with Matplotlib.

enter image description here

Upvotes: 2

Related Questions