Digital Geography

6. March 2018

openrouteservice v4.5 is released

We’re happy to announce the release of v4.5 of openrouteservice, which exposes unique services for two of our core API’s, routing and isochrones. Now you can restrict routes to avoid crossing borders and get instant population counts on isochrones.

openrouteservice is operative since more than 10 years and at home at the HeiGIT institute in Heidelberg. It’s strongly anchored in the humanitarian community since its creation on and continues to play a vital role during natural and humanitarian catastrophes via Disaster ORS. We’re also trying to serve the rest of the world with open-source routing capabilities, which host increasingly unique routing features.

Did you know?

We will start a series soon featuring Jupyter notebooks for relevant use cases which can be covered with our growing API stack. So stay tuned.

Restricting Borders in openrouteservice

Have you ever wanted to route between countries in Europe but only cross Schengen borders? Or maybe route from Detroit to Buffalo without crossing into Canada? With openrouteservice you can! With our new border crossing restrictions on driving profiles, you can tell the openrouteservice API to avoid: all borders, controlled borders or specific countries. For example,
would tell the routing engine to avoid crossing controlled borders, but still allow crossing of open borders (i.e. Schengen borders). To avoid specific countries, you can make use of the avoid_countries option. E.g.
tells the service to avoid crossing into Belgium and Luxembourg. Get the full list of ID country mappings here.

Restricting borders is useful for logistics companies all over the world to avoid national driving restrictions and/or unnecessary delays at customs checkpoints. This is an example for a route from Ludwigshafen, Germany, to Milan, Italy, detouring over Austria to avoid Switzerland. A common use case for central European companies, Swiss customs is known to behave rather particular (no offense, Switzerland, we all love you).

Population Statistics for Isochrones

GHSL – Global Human Settlement Layer

We are also excited about one handy new feature for the isochrones API. From now on, you can optionally return the population count for each isochrone you’re calculating. This is an imperative step for inclusive reachability analysis. The dataset, which makes this possible, is published by the European Commission in their Global Human Settlement Program. It features 250 m x 250 m cell size across the globe and is the finest grained open dataset of its kind. To access this feature in runtime you have to specify it as attribute in the isochrone request:
which will respond the total population count in this polygon:


Responding in GeoJSON

Last but not least, we have finally introduced the much longed feature to respond in GeoJSON. With your geospatial libraries, there’s no more manual JSON parsing necessary. This can also be useful for a quick look at the geometry of routes. The response can be directly imported into QGIS via “add vector layer”, selecting “protocol” as the source type, and entering the url (with the format=geojson url parameter)!

QGIS Bonus

Here’s also a quick population hack for QGIS Python console (note, only for v3.0, slightly different in v2.18). Population statistics are not yet available in the QGIS plugin and anyways, just for the fun of pyqgis. Insert your own API key, make sure your first layer is a point layer (or specify another ID) and paste it into the QGIS Python console:

import sys
sys.path.insert(0, '/home/nilsnolde/anaconda3/lib/python3.6/site-packages/') # first install openrouteservice package via pip
from openrouteservice import client, isochrones
clnt = client.Client(key='your-ḱey')
features_in = iface.mapCanvas().layer(0).getFeatures(QgsFeatureRequest()) # creates iterator for all features of layer_id=0
poly_out = QgsVectorLayer("Polygon?crs=EPSG:4326", "Isochrones", "memory") # create layer
poly_out.dataProvider().addAttributes([QgsField("AA_MINS", QVariant.Int)],
                                      [QgsField("TOTAL_POP", QVariant.Int)]) # add fields
for point in features_in:
    coords_point = point.geometry().asPoint()
    response = clnt.isochrones(locations=coords, # let openrouteservice module create the request
    isochrones = response['features']
    for idx, isochrone in enumerate(isochrones):
        isochrone_coords = [QgsPointXY(x, y) for x, y in isochrones[idx]['geometry']['coordinates'][0]]
        isochrone_props = isochrones[idx]['properties']
        feat = QgsFeature()short-announcement-ors
        feat.setAttributes([isochrone_props['value']/60, isochrone_props['total_pop']])


ORS on GitHub | ORS 4.5 Changelog | ORS Route Planning | ORS API Documentation