Digital Geography

1. June 2019

ArcGIS REST API and QGIS: a practical example

The ArcGIS REST API provides some interesting endpoints which can be used for free with a developer account. But how to do this in QGIS as you might not have a licensed ArcGIS Desktop license at hand: A short example using isochrones or “service areas” as Esri calls them.

Preparation: The App Registration

Once you have a developer account enabled, you should register a new app which is needed for getting the tokens for your queries. As said, it is a bit more complicated compared to Here with their api-keys.
Yet the developer account is packed with 50 credits per month. But what the heck are those credits worth? To bring it into perspective there is a nice listing on the pricing page of Esri’s developer program:
  • calculating 10.000 simple routes
  • or 100 service areas
  • or storing approx. 200mb of feature services online
So create an app and remember the client-id and secret key of your app as described here. Once done, we can get a token:

Application with needed details

The Script for Isochrones

There is a short example regarding the token mechanism on the dev pages. Here a bit cleaned up:
import requests
url = "https://www.arcgis.com/sharing/rest/oauth2/token"
payload = "expiration=20160&client_id=YOUR_FANCY_client_ID&client_secret=YOUR_FANCY_client_secret&grant_type=client_credentials"
headers = {
    'content-type': "application/x-www-form-urlencoded",
    'accept': "application/json",
    }
response = requests.request("POST", url, data=payload, headers=headers)
token = response.json()["access_token"]
print(token)
As we do have the token, we can get the Service Area for Berlin:
url = "http://route.arcgis.com/arcgis/rest/services/World/ServiceAreas/NAServer/ServiceArea_World/solveServiceArea?facilities=13.404954,52.520008&defaultBreaks=20&outSR=4326&f=pjson&token=" + token
response = requests.request("GET", url)
coordinates = response.json()["saPolygons"]["features"][0]["geometry"]["rings"][0]
As you can see in the last line I am only accessing one polygon (I am not taken any rings as I am just interested in the 20min isochrone). The API gives you plenty of custom parameters for the service area and also offers a result in the spatial reference of your choice. So no fancy reprojecting needed. Unfortunately the response is not a straightforward geojson but more an arcgis json. Take this into account when you’re thinking about saving the results (which might not be allowed with a non-paid developer account). For the time being, I am only adding the result as a memory layer:
QgsVertices = []
for pair in coordinates:
    QgsVertices.append(QgsPointXY(pair[0],pair[1]))
geom = QgsGeometry.fromPolygonXY([QgsVertices])
layer = QgsVectorLayer('Polygon?crs=epsg:4326', 'Service Area 20min' , 'memory')
feat = QgsFeature()
feat.setGeometry(geom)
prov = layer.dataProvider()
prov.addFeatures([feat])
layer.updateExtents()
# Add the layer to the Layers panel
QgsProject.instance().addMapLayer(layer)
And bamm: there it is! Esri isochrones in QGIS. Will I go to hell for this? maybe…

Esri’s service areas in QGIS

And in the end I think the result is more appealing than the ones from Here, and others. But more on this later on.