PlotGeometry
¶The PlotGeometry
class is an addition to MetPy's declarative plotting interface, allowing users to generate plots of collections of Shapely objects. The primary use case is to visualize data from GeoJSON and Shapefile formats.
Useful attributes of this class are
geometry
: A collection of Shapely objects to be plottedstroke
: A single string or collection of strings denoting the color(s) to outline the plotted geometryfill
: A single string or collection of strings denoting the color(s) to fill the plotted geometrylabels
: A collection of strings or numbers to label the plotted geometrylabel_fontsize
: A string ('xx-small' to 'xx-large') or number (in points) to set the font size of labelslabel_facecolor
: A single string or collection of strings denoting the font color(s) for labelslabel_edgecolor
: A single string or collection of strings denoting the outline color(s) for labelsmarker
: Any acceptable matplotlib marker (only for use when plotting points)Only geometry
is required. All other attributes have default values.
import collections
import cartopy.crs as ccrs
import matplotlib.patheffects as PathEffects
from shapely.geometry import LineString, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon
from traitlets import Bool, Float, HasTraits, Instance, Int, observe, Unicode, Union, validate
from metpy.plots._mpl import TextCollection
from metpy.plots.declarative import Panel
The following example use cases demonstrate the ability for PlotGeometry
to plot polygons, lines, and points, as well as labels for those features.
GeoJSON and Shapefile files were retrieved from NOAA's Storm Prediction Center (https://www.spc.noaa.gov/gis/) and National Hurricane Center (https://www.nhc.noaa.gov/gis/)
import geopandas
from metpy.plots.declarative import PlotGeometry, MapPanel, PanelContainer
spc_day_1 = geopandas.read_file('spc_day1otlk_20210714_1300.geojson')
spc_day_1
DN | VALID | EXPIRE | ISSUE | LABEL | LABEL2 | stroke | fill | geometry | |
---|---|---|---|---|---|---|---|---|---|
0 | 2 | 202107141300 | 202107151200 | 202107141405 | TSTM | General Thunderstorms Risk | #55BB55 | #C1E9C1 | MULTIPOLYGON (((-96.55039 48.99288, -96.43000 ... |
1 | 3 | 202107141300 | 202107151200 | 202107141405 | MRGL | Marginal Risk | #005500 | #66A366 | MULTIPOLYGON (((-82.72035 42.38458, -84.24000 ... |
2 | 4 | 202107141300 | 202107151200 | 202107141405 | SLGT | Slight Risk | #DDAA00 | #FFE066 | MULTIPOLYGON (((-87.43000 41.86000, -91.13000 ... |
3 | 5 | 202107141300 | 202107151200 | 202107141405 | ENH | Enhanced Risk | #FF6600 | #FFA366 | POLYGON ((-87.42000 43.67000, -88.44000 42.650... |
geo = PlotGeometry()
geo.geometry = spc_day_1['geometry']
geo.stroke = spc_day_1['stroke']
geo.fill = spc_day_1['fill']
geo.labels = spc_day_1['LABEL']
geo.label_fontsize = 'large'
panel = MapPanel()
panel.area = [-125, -70, 20, 55]
panel.projection = 'lcc'
panel.layers = ['lakes', 'land', 'ocean', 'states', 'coastline', 'borders']
panel.title = 'SPC Day 1 Convective Outlook'
panel.plots = [geo]
pc = PanelContainer()
pc.size = (15, 10)
pc.panels = [panel]
pc.show()
irma_wind_field = geopandas.read_file('https://www.nhc.noaa.gov/gis/examples/al112017_fcst_020.zip')
irma_wind_field = irma_wind_field.dissolve(by='RADII', aggfunc='mean')
irma_wind_field
geometry | STORMNUM | TAU | NE | SE | SW | NW | |
---|---|---|---|---|---|---|---|
RADII | |||||||
34.0 | POLYGON ((-56.10040 18.76072, -56.06059 18.758... | 11.0 | 36.0 | 141.428571 | 112.857143 | 77.142857 | 117.142857 |
50.0 | MULTIPOLYGON (((-56.15433 17.59726, -56.13607 ... | 11.0 | 36.0 | 62.857143 | 58.571429 | 44.285714 | 62.857143 |
64.0 | MULTIPOLYGON (((-56.17722 17.09863, -56.16813 ... | 11.0 | 18.0 | 28.750000 | 27.500000 | 23.750000 | 28.750000 |
geo = PlotGeometry()
geo.geometry = irma_wind_field['geometry']
geo.fill = ['navy', 'orange', 'maroon']
geo.stroke = 'white'
geo.labels = irma_wind_field.index.astype(int).astype(str) + ' kt'
# PlotGeometry provides default fill and stroke for geometry when not specified
panel = MapPanel()
panel.area = [-75, -45, 12, 25]
panel.projection = ccrs.PlateCarree()
panel.layers = ['lakes', 'land', 'ocean', 'states', 'coastline', 'borders']
panel.title = 'Hurricane Irma Wind Radii'
panel.plots = [geo]
pc = PanelContainer()
pc.size = (15, 10)
pc.panels = [panel]
pc.show()
irma_probs = geopandas.read_file('https://www.nhc.noaa.gov/gis/examples/2016100512_wsp_120hr5km.zip')
irma_probs
PERCENTAGE | geometry | |
---|---|---|
0 | <5% | MULTIPOLYGON (((-249.121 11.205, -249.121 11.2... |
1 | 5-10% | MULTIPOLYGON (((-75.186 19.522, -75.186 19.567... |
2 | 10-20% | MULTIPOLYGON (((-75.186 19.567, -75.186 19.612... |
3 | 20-30% | MULTIPOLYGON (((-75.096 19.612, -75.096 19.657... |
4 | 30-40% | MULTIPOLYGON (((-75.141 19.702, -75.141 19.747... |
5 | 40-50% | MULTIPOLYGON (((-73.972 19.747, -73.972 19.792... |
6 | 50-60% | MULTIPOLYGON (((-75.096 19.837, -75.096 19.881... |
7 | 60-70% | MULTIPOLYGON (((-73.927 19.881, -73.927 19.926... |
8 | 70-80% | MULTIPOLYGON (((-75.006 19.881, -75.006 19.926... |
9 | 80-90% | MULTIPOLYGON (((-75.051 19.971, -75.051 20.016... |
10 | >90% | MULTIPOLYGON (((-62.284 24.467, -62.284 24.512... |
geo = PlotGeometry()
geo.geometry = irma_probs['geometry']
geo.fill = ['none', 'darkgreen', 'green', 'lime', 'gold', 'goldenrod', 'darkgoldenrod', 'orange', 'red', 'darkred', 'violet']
geo.stroke = 'none'
geo.labels = irma_probs['PERCENTAGE']
geo.label_facecolor = 'white'
panel = MapPanel()
panel.area = [-90, -55, 15, 42]
panel.projection = ccrs.PlateCarree()
panel.layers = ['lakes', 'land', 'ocean', 'states', 'coastline', 'borders']
panel.title = 'Hurricane Irma Forecast'
panel.plots = [geo]
pc = PanelContainer()
pc.size = (15, 10)
pc.panels = [panel]
pc.draw()
irma_forecast = geopandas.read_file('https://www.nhc.noaa.gov/gis/examples/al112017_5day_020.zip')
irma_forecast
STORMNAME | STORMTYPE | ADVDATE | ADVISNUM | STORMNUM | FCSTPRD | BASIN | geometry | |
---|---|---|---|---|---|---|---|---|
0 | Irma | HU | 500 AM AST Mon Sep 04 2017 | 20 | 11.0 | 120.0 | AL | LINESTRING (-52.30000 16.90000, -53.90000 16.7... |
geo = PlotGeometry()
geo.geometry = irma_forecast['geometry']
geo.labels = irma_forecast['STORMNAME']
panel = MapPanel()
panel.area = [-85, -45, 12, 25]
panel.projection = ccrs.PlateCarree()
panel.layers = ['lakes', 'land', 'ocean', 'states', 'coastline', 'borders']
panel.title = 'Hurricane Irma Forecast'
panel.plots = [geo]
pc = PanelContainer()
pc.size = (15, 10)
pc.panels = [panel]
pc.show()
irma_best_track = geopandas.read_file('https://www.nhc.noaa.gov/gis/examples/al112017_best_track.zip')
irma_best_track
STORMNAME | DTG | YEAR | MONTH | DAY | HHMM | MSLP | BASIN | STORMNUM | STORMTYPE | INTENSITY | SS | LAT | LON | geometry | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | GENESIS023 | 2.017083e+09 | 2017.0 | 08 | 27.0 | 1800 | 0.0 | al | 11.0 | DB | 25.0 | 0.0 | 11.5 | -16.0 | POINT (-16.00000 11.50000) |
1 | GENESIS023 | 2.017083e+09 | 2017.0 | 08 | 28.0 | 0000 | 0.0 | al | 11.0 | DB | 25.0 | 0.0 | 11.5 | -17.8 | POINT (-17.80000 11.50000) |
2 | INVEST | 2.017083e+09 | 2017.0 | 08 | 28.0 | 0600 | 1009.0 | al | 11.0 | DB | 25.0 | 0.0 | 11.6 | -19.3 | POINT (-19.30000 11.60000) |
3 | INVEST | 2.017083e+09 | 2017.0 | 08 | 28.0 | 1200 | 1009.0 | al | 11.0 | LO | 25.0 | 0.0 | 11.9 | -20.5 | POINT (-20.50000 11.90000) |
4 | INVEST | 2.017083e+09 | 2017.0 | 08 | 28.0 | 1800 | 1008.0 | al | 11.0 | LO | 25.0 | 0.0 | 12.3 | -21.0 | POINT (-21.00000 12.30000) |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
57 | IRMA | 2.017091e+09 | 2017.0 | 09 | 11.0 | 0000 | 942.0 | al | 11.0 | HU | 90.0 | 2.0 | 26.8 | -81.7 | POINT (-81.70000 26.80000) |
58 | IRMA | 2.017091e+09 | 2017.0 | 09 | 11.0 | 0600 | 961.0 | al | 11.0 | HU | 75.0 | 1.0 | 28.2 | -82.2 | POINT (-82.20000 28.20000) |
59 | IRMA | 2.017091e+09 | 2017.0 | 09 | 11.0 | 1200 | 970.0 | al | 11.0 | TS | 60.0 | 0.0 | 29.6 | -82.7 | POINT (-82.70000 29.60000) |
60 | IRMA | 2.017091e+09 | 2017.0 | 09 | 11.0 | 1800 | 980.0 | al | 11.0 | TS | 45.0 | 0.0 | 30.9 | -83.5 | POINT (-83.50000 30.90000) |
61 | IRMA | 2.017091e+09 | 2017.0 | 09 | 12.0 | 0000 | 986.0 | al | 11.0 | TS | 40.0 | 0.0 | 31.9 | -84.4 | POINT (-84.40000 31.90000) |
62 rows × 15 columns
geo = PlotGeometry()
geo.geometry = irma_best_track['geometry']
geo.fill = 'maroon'
geo.stroke = 'white'
geo.marker = '*'
geo.labels = irma_best_track['INTENSITY'].astype(int).astype(str) + ' kt'
geo.label_fontsize = 'large'
panel = MapPanel()
panel.area = [-85, -65, 17, 30]
panel.projection = ccrs.PlateCarree()
panel.layers = ['lakes', 'land', 'ocean', 'states', 'coastline', 'borders']
panel.title = 'Hurricane Irma Best Track'
panel.plots = [geo]
pc = PanelContainer()
pc.size = (15, 10)
pc.panels = [panel]
pc.show()
Shapefile of US primary roads retrieved from Data.gov (https://catalog.data.gov/dataset/tiger-line-shapefile-2016-nation-u-s-primary-roads-national-shapefile)
Shapefile of US cities retrieved from Princeton University Library (https://maps.princeton.edu/catalog/stanford-bx729wr3020)
roads = geopandas.read_file('https://www2.census.gov/geo/tiger/TIGER2016/PRIMARYROADS/tl_2016_us_primaryroads.zip')
interstates = roads[roads['RTTYP'] == 'I']
interstates
LINEARID | FULLNAME | RTTYP | MTFCC | geometry | |
---|---|---|---|---|---|
3 | 1105056901124 | I- 405 | I | S1100 | LINESTRING (-122.67960 45.54082, -122.67968 45... |
4 | 1105056901128 | I- 405 | I | S1100 | LINESTRING (-122.67096 45.50685, -122.67103 45... |
5 | 1105056901162 | I- 70 | I | S1100 | LINESTRING (-85.22090 39.85346, -85.22171 39.8... |
10 | 1103970863393 | I- 29 | I | S1100 | LINESTRING (-94.60128 39.18727, -94.60138 39.1... |
18 | 1105640135939 | I- 85 | I | S1100 | LINESTRING (-80.38962 35.71971, -80.38906 35.7... |
... | ... | ... | ... | ... | ... |
12490 | 1105556222128 | I- 69 | I | S1100 | LINESTRING (-95.13725 30.27150, -95.13524 30.2... |
12491 | 1105556223312 | I- 69 | I | S1100 | LINESTRING (-95.25483 30.03960, -95.25376 30.0... |
12492 | 1105556223318 | I- 69 | I | S1100 | LINESTRING (-95.07014 30.37501, -95.07023 30.3... |
12503 | 1105576057973 | I- 25 | I | S1100 | LINESTRING (-104.65907 36.21830, -104.65899 36... |
12504 | 1105576057976 | I- 25 | I | S1100 | LINESTRING (-104.99942 35.77158, -104.99938 35... |
6016 rows × 5 columns
cities = geopandas.read_file('http://stacks.stanford.edu/file/druid:bx729wr3020/data.zip')
large_cities = cities[cities['POP_2010'] > 100000]
large_cities
GNIS_ID | ANSICODE | FEATURE | FEATURE2 | NAME | POP_2010 | COUNTY | COUNTYFIPS | STATE | STATE_FIPS | LATITUDE | LONGITUDE | PopPlLat | PopPlLong | ELEV_IN_M | ELEV_IN_FT | geometry | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
177 | 1028945.0 | 1036030 | Civil | County Seat | Fargo | 105549.0 | Cass | 017 | ND | 38 | 46.877186 | -96.789803 | 46.877186 | -96.789803 | 275.0 | 902.0 | POINT (-96.78980 46.87719) |
373 | 962684.0 | 979426 | Civil | County Seat | Rochester | 210565.0 | Monroe | 055 | NY | 36 | 43.154784 | -77.615557 | 43.154784 | -77.615557 | 154.0 | 505.0 | POINT (-77.61556 43.15478) |
378 | 966966.0 | 979539 | Civil | County Seat | Syracuse | 145170.0 | Onondaga | 067 | NY | 36 | 43.048122 | -76.147424 | 43.048122 | -76.147424 | 121.0 | 397.0 | POINT (-76.14742 43.04812) |
386 | 973345.0 | 978764 | Civil | County Seat | Buffalo | 261310.0 | Erie | 029 | NY | 36 | 42.886447 | -78.878369 | 42.886447 | -78.878369 | 183.0 | 600.0 | POINT (-78.87837 42.88645) |
426 | 611832.0 | 618227 | Civil | -999 | Lowell | 106519.0 | Middlesex | 017 | MA | 25 | 42.633425 | -71.316172 | 42.633425 | -71.316172 | 36.0 | 118.0 | POINT (-71.31617 42.63342) |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
38126 | 971944.0 | -999 | Populated Place | -999 | The Bronx | 1408473.0 | Bronx | 005 | NY | 36 | 40.849928 | -73.866179 | 40.850100 | 40.850100 | 16.0 | 52.0 | POINT (-73.86618 40.84993) |
38127 | 971945.0 | -999 | Populated Place | -999 | Manhattan | 1619090.0 | New York | 061 | NY | 36 | 40.783462 | -73.966186 | 40.783435 | -73.966250 | 35.0 | 115.0 | POINT (-73.96619 40.78346) |
38128 | 1783503.0 | -999 | Populated Place | -999 | Brooklyn | 2565635.0 | Kings County | 047 | NY | 36 | 40.650093 | -73.949564 | 40.650104 | -73.949582 | 15.0 | 49.0 | POINT (-73.94956 40.65009) |
38129 | 971983.0 | -999 | Populated Place | -999 | Queens | 2272771.0 | Queens County | 081 | NY | 36 | 40.750162 | -73.797445 | 40.749824 | -73.797634 | 12.0 | 39.0 | POINT (-73.79745 40.75016) |
38130 | 1802959.0 | -999 | Populated Place | -999 | Staten Island | 470728.0 | Richmond County | 085 | NY | 36 | 40.583281 | -74.149812 | 40.583438 | -74.149588 | 50.0 | 164.0 | POINT (-74.14981 40.58328) |
284 rows × 17 columns
geo = PlotGeometry()
geo.geometry = interstates['geometry']
geo.stroke = 'darkgreen'
geo2 = PlotGeometry()
geo2.geometry = large_cities['geometry']
geo2.labels = large_cities['NAME']
geo2.fill = 'black'
geo2.marker = 'o'
geo2.label_edgecolor = 'white'
panel = MapPanel()
panel.area = 'sc+'
panel.projection = ccrs.PlateCarree()
panel.layers = ['land', 'ocean', 'states', 'coastline', 'borders', 'lakes']
panel.title = 'US Cities and Interstates'
panel.plots = [geo, geo2]
pc = PanelContainer()
pc.size = (15, 10)
pc.panels = [panel]
pc.show()