Reputation: 513
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
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.
Upvotes: 2