Search code examples
python-3.xmatplotlibshapefileshapelycartopy

Cartopy Plot Specific Attributes Contained In Shapefile


I have a shapefile of major roadways in New Hampshire (TIGER/Line) obtained from the U.S Census Bureau (file found here), and am attempting to plot them using the Cartopy/Matplotlib tandem.

The Shapefile's Attributes

The shapefile attribute is split into four classes: LINEARID, FULLNAME, RTTYP, & MTFCC

First Approach | Plot All Lines

The first approach was to load the shapefile in using cartopy.feature and plot it, which can be seen in the following code snippet. This worked as expected, and plotted every road line contained within the shapefile:

from cartopy.io.shapereader import Reader
from cartopy.feature import ShapelyFeature
roads = '/path/to/file/majorroads.shp'
roads_feature = ShapelyFeature(Reader(roads).geometries(), crs.LambertConformal(), facecolor='none', edgecolor='gray')
ax.add_feature(roads_feature, linewidth=0.75)

Second Approach | Plot Specific Attribute

The second approach was to use the Cartopy Reader to locate and only plot lines that met a specific attribute. After reading this article from NASA, I used examples to write the following code:

from cartopy.io.shapereader import Reader
from cartopy.feature import ShapelyFeature
roads = '/path/to/file/majorroads.shp'
roads_feature = Reader(roads)
parts = roads_feature.records()
for part in parts:
    if part.attributes['FULLNAME'] == 'US Hwy 202':
        ax.add_geometries(part.attributes, linewidth=0.50, facecolor='none', edgecolor='gray')

This did not plot the desired lines in the shapefile. What corrections can be made to ensure this code works correctly?


Solution

  • The best solution to execute this task is to utilize the Geopandas library in Python. My code was inspired from this web article, however I've expanded on its use somewhat in the answer below.

    Code Snippet

    import geopandas as gpd
    data = gpd.read_file('/path/to/file/majorroads.shp')
    sorted = data[(data.RTTYP == 'I') | (data.RTTYP == 'U') | (data.FULLNAME == 'State Rte 101') | (data.FULLNAME == 'Rte 101')]
    ax.add_geometries(sorted.geometry, crs=crs.LambertConformal(), linewidth=1.00, facecolor='none', edgecolor='gray')
    

    Important Notes

    The shapefile is read into a familiar dataframe structure as seen in Pandas use. You'll notice: data[(data.RTTYP == 'I') | (data.RTTYP == 'U') | (data.FULLNAME == 'State Rte 101') | (data.FULLNAME == 'Rte 101')]

    This use of element-wise logic was derived from this example, which can be expanded to other larger, data-rich shapefiles