GeoPandas Demo: Get Counties

This example demonstrates how to grab data from an ArcGIS MapService and pull it into a GeoPandas data frame.


In [ ]:
import requests
import pandas as pd
import geopandas as gpd

%matplotlib inline

Fetching the data

  • Build the request
  • Send the request, receive the response

In [ ]:
#Build the request and parameters to fetch county features
#  from the NOAA ArcGIS map server end point
stateFIPS = '37' #This is NC

url = 'https://nowcoast.noaa.gov/arcgis/rest/services/nowcoast/mapoverlays_political/MapServer/find'
params = {'searchText':stateFIPS,
          'contains':'true',
          'searchFields':'STATEFP',
          'sr':'',
          'layers':'2',
          'layerDefs':'',
          'returnGeometry':'true',
          'maxAllowableOffset':'',
          'geometryPrecision':'',
          'dynamicLayers':'',
          'returnZ':'false',
          'returnM':'false',
          'gdbVersion':'',
          'returnUnformattedValues':'false',
          'returnFieldName':'false',
          'datumTransformations':'',
          'layerParameterValues':'',
          'mapRangeValues':'',
          'layerRangeValues':'',
          'f':'json'}

In [ ]:
#Fetch the data
response = requests.get(url,params)

Examining the response

  • Convert the response to a JSON object
  • Examine its structure
  • Extract the attributes and geometry elements.

In [ ]:
#Convert to a JSON object (i.e. a dictionary)
respons_js = response.json()

In [ ]:
#The 'results' object contains a record for each county returned
results = respons_js['results']
len(results)

In [ ]:
#Within each item in the results object are the following items
results[0].keys()

In [ ]:
#The 'attributes' item contains the feature attributes
results[0]['attributes']

In [ ]:
#And the geometry object contains the shape
results[0]['geometry']

Convert the elements to dataFrames

  • Creating a dataFrame from the Results object
  • "Exploding" the values in the attributes and geometry columns
  • Concatenating dataFrames lengthwise (adding columns)

In [ ]:
#Create a dataFrame from the results, 
#  keeping just the attributes and geometry objects
df = pd.DataFrame(results,columns=('attributes','geometry'))
df.head()

In [ ]:
#Explode the dictionary values into fields
dfCounties = df['attributes'].apply(pd.Series)
dfGeom = df['geometry'].apply(pd.Series)

In [ ]:
#Combine the two
dfAll = pd.concat((dfCounties,dfGeom),axis='rows')
dfAll.columns

Converting the geometry coordinates to a geometric feature

  • Exploring the 'rings' object
  • Exploring the shapely package
  • Using shapely to create features
  • Converting the dataFrame to geodataFrame
  • Plotting the output

In [ ]:
#Demo creating a shapely polygnon from the JSON ring
rings = dfAll['rings'][0]
print "There is/are {} ring(s)".format(len(rings))
print "There are {} vertices in the first ring".format(len(rings[0]))
print "The first vertex is at {}".format(rings[0][0])

In [ ]:
from shapely.geometry import LinearRing
from shapely.geometry import Polygon
ring = rings[0]
r = LinearRing(ring)
s = Polygon(r)

In [ ]:
#https://shapely.readthedocs.io/en/latest/manual.html#polygons
from shapely.geometry import Polygon
from shapely.geometry import LinearRing
def polyFromRing(ring):
    r = LinearRing(ring)
    s = Polygon(r)
    return r
dfAll['geometry']=dfAll.apply(lambda x: Polygon(x.rings[0]),axis=1)

In [ ]:
gdf=gpd.GeoDataFrame(dfAll)

In [ ]:
gdf[gdf['NAME'] == 'Durham'].plot();

In [ ]:
gdf.to_csv("counties_{}.csv".format(stateFIPS))