How to create isochrones with QGIS

Gispo Ltd.

Version: 2021-12-16

Documentation on calculating isochrones for railway stations using OpenStreetMap data

1 Creating railway station isochrones with QGIS

The goal was to create isodistance curves as well as isochrones when traveling by foot and by bike to all railway station and metro station platform levels in the Helsinki region. Since HSL uses OpenStreetMap for routing to railway and metro station platforms, the data available in OpenStreetMap is high quality and can be used as such. At some stations, some entrances and paths were updated in OpenStreetMap before the analysis.

Future Länsimetro specific details are listed in orange boxes, and you may ignore the orange boxes if you are only interested in existing stations.

Possible problems or caveats in OSM data are listed in purple boxes.

The process takes place in a few steps:

  1. Finding platform entrances using OpenStreetMap Overpass API
  2. Saving entrance and station points and linking them in QGIS
  3. Installing Graphhopper server and QGIS Catchment plugin
  4. Selecting the desired isochrone distances and settings
  5. Admiring your results.

1.1 How to find stations and platform entrances on Overpass API

Overpass API is the official API to access OpenStreetMap data, and it is queried using the Overpass Query Language.

All the railway platforms in HSY area are in OSM as multipolygons, polygons or linestrings. Polygons and linestrings are ways (closed or open) in OpenStreetMap. In case of a multipolygon platform (Ilmala, Rautatieasema), it is a relation instead. Overpass query to get nodes that make up the railway platforms is as follows:

(
  (
    way["railway"="platform"]({{bbox}});
    node(w);
  );
  (
    rel["railway"="platform"]({{bbox}});
    way(r);
    node(w);
  );
)->.platform_nodes;

Go through all the nodes in the platforms and find attached walkways:

(
    way["highway"="steps"]({{bbox}})(bn.platform_nodes);
    way["highway"="elevator"]({{bbox}})(bn.platform_nodes);
    way["highway"="footway"]({{bbox}})(bn.platform_nodes);
    way["highway"="pedestrian"]({{bbox}})(bn.platform_nodes);
    way["highway"="path"]({{bbox}})(bn.platform_nodes);
    way["foot"]({{bbox}})(bn.platform_nodes);
);
node(w)->.walkway_nodes;

Find the nodes that are attached to both walkways and platforms:

node.platform_nodes.walkway_nodes;
out geom;

On some stations, this will return extra points on the platform edges that could be removed from the analysis without affecting the results. However, they will only slow down the analysis a little, so it makes no sense to go through every point and check if it is strictly needed.

So, our complete Overpass query becomes

(
  (
    way["railway"="platform"]({{bbox}});
    node(w);
  );
  (
    rel["railway"="platform"]({{bbox}});
    way(r);
    node(w);
  );
)->.platform_nodes;
(
    way["highway"="steps"]({{bbox}})(bn.platform_nodes);
    way["highway"="elevator"]({{bbox}})(bn.platform_nodes);
    way["highway"="footway"]({{bbox}})(bn.platform_nodes);
    way["highway"="pedestrian"]({{bbox}})(bn.platform_nodes);
    way["highway"="path"]({{bbox}})(bn.platform_nodes);
    way["foot"]({{bbox}})(bn.platform_nodes);
);
node(w)->.walkway_nodes;
node.platform_nodes.walkway_nodes;
out geom;

1.2 How to save the results of the query

The easiest way to get all nodes in the query is the Overpass Turbo service https://overpass-turbo.eu/s/1du9 . Zooming the map automatically sets the bbox variable for the overpass query, so make sure the map is zoomed to the area you want and click Run.

Overpass Turbo

Verify that the results contain all the nodes that you wish to include. At the time of the writing, some errors were fixed and missing connections to the platforms were added to OSM. Most platform entrances were already correct, thanks to HSL editors over the years. Some stations (notably Ilmala, Kerava and Järvenpää) required connecting paths to the platforms or creating proper platform polygons. The fixes were done by comparing aerial photographs and HSY station platform schematics to the overpass query results.

OSM editors may always make new errors and remove accidentally some of the connections on the stations. Especially stairs and elevators are not always properly connected to the platform edges by OSM editors, and this means they may be missing in future results. If there are missing entrances, please fix all the data in OSM by connecting them to the platform polygons/linestrings before continuing.

After the query is finished, the data can be exported by clicking on Export. At the time of the writing the number of nodes is 725. Save the file as e.g. entrances.geojson, open it in QGIS and verify that all the nodes are present.

Entrances to Kerava platforms

To group platform entrances by station name, we also want the station points. This is done with a simple Overpass query

node["railway"="station"]({{bbox}});
out geom;

Run this and save the results as e.g. stations.geojson.

Note that “Pasilan autojuna-asema” should be removed manually from both stations and entrances, since it doesn’t offer any local traffic.

Missing future Länsimetro stations were added as points located at the underground metro platforms. This is the same way existing metro station locations are saved in OpenStreetMap.

Missing future Länsimetro station entrances were approximated based on public plans and schematics materials offered by Espoo around each of the Länsimetro stations. All station plans offer links to detail plans and reference schematics on the planned buildings at each future station, so the location of the doors (and levels) at each entrance can be approximated. An example link to the plans around the Soukka station.

An example from Soukka reference plan

In addition, Länsimetro provided a table that contains internal walking distances in meters + seconds on escalator/elevator from the metro platform to each of the entrances at different levels. These numbers were added individually to each mapped entrance to take into account later. In some cases, the entrances had to be moved further to connect to the surrounding walking network, as they are currently located inside construction sites. This added distance was also added to the walking distance to the platform.

Espoonlahti entrances had to be moved outside the construction site

Giving each platform entrance the name of the railway station is easiest done with the QGIS Vector analysis tool “Distance to nearest hub (reference points)”. This will generate a point layer that contains the name of the station (and distance of the entrance to the station node):

Getting name of railway station for each entrance point

Another problem in OSM data is that sometimes, areas around a station entrance may be marked with a walkable polygon, with the station doors only connecting to a walkable polygon but no paths. GraphHopper, as its name suggests, uses a graph algorithm, and is unable to do any routing through a polygon; it requires paths. Especially some underground stations (Itäkeskus, Puotila, Kamppi, Kivistö) were surrounded above the ground by a walkable polygon with no paths from the entrance building. This problem might be detected only after doing the routing and finding missing areas in the resulting isochrones.

In these cases, paths had to be added to connect the entrance buildings across the pedestrian areas to paths outside the pedestrian area. A notable example is Itäkeskus bus terminal and Tallinnanaukio, which required adding lots of walkable paths to connect station entrances to the shopping mall entrances and all neighboring paths. Smaller fixes were made to a large amount of pedestrian squares around many stations, considering people walking from the direction of the station.

Paths had to be added all across Itäkeskus Tallinnanaukio and bus terminal

1.3 How to setup Graphhopper server and QGIS plugin

Graphhopper is an open-source routing engine that uses OpenStreetMap roads and paths out of the box. It is most easily installed directly on an empty Ubuntu server with Java VM and their own README instructions:

sudo apt update
sudo apt install default-jre
wget https://graphhopper.com/public/releases/graphhopper-web-4.0.jar https://raw.githubusercontent.com/graphhopper/graphhopper/4.x/config-example.yml

The config-example.yml file has to be updated to activate walk and bike routing, and to allow access to the server from outside:

profiles:
    - name: hike
        vehicle: hike
        weighting: shortest
    - name: bike
        vehicle: bike
        weighting: custom
        custom_model: {
          "speed": [
            {
              "if": "true",
              "limit_to": 15
            },
            {
              "if": "road_class == MOTORWAY",
              "multiply_by": 0
            }
          ]
        }
...
server:
  application_connectors:
  - type: http
    port: 8989
    # COMMENT OUT THE NEXT LINE!
    # bind_host: localhost

The hiking profile has speed of 5 km/h on flat ground (3 km/h on stairs). The bike profile speed varies from 2 km/h (when pushing the bike on stairs on stations) all the way to 15 km/h (when riding the bike on a separate bike lane). If a regular (not custom) bike profile is used instead, the maximum speed will be 18 km/h.

Finally, the local OSM extract has to be downloaded and GraphHopper has to be started with enough memory for the Java VM:

wget https://download.geofabrik.de/europe/finland-latest.osm.pbf
java -Xmx12g -Xms12g -Ddw.graphhopper.datareader.file=finland-latest.osm.pbf -jar *.jar server config-example.yml

First startup will be slow. GraphHopper will read the whole Finland extract and construct routing graphs for all the modes listed in the config file. If you change config or want to update the data, you have to delete the graph-cache directory and restart Graphhopper.

The Catchment QGIS plugin needs to be installed from the QGIS Plugins repository. Start up the plugin and fill in your Graphhopper URL (e.g. http://52.59.201.37:8989 or wherever your installation is) in the Settings tab.

Catchment plugin settings

1.4 How to calculate isochrones

Then you may calculate the isochrone for any layer in QGIS by selecting the layer name, distance in meters or minutes and, if you selected minutes, the mode of transport, i.e. Walking or Cycling. This way you can calculate isochrones for all the station points. Distance divisions may be set to 10 to calculate all distances from 200 to 2000 meters at the same time, or 3 to calculate distances of 5, 10 and 15 minutes.

Catchment plugin options and extra options

Some new features were added to the plugin to make our calculations easier. Calculating isochrones for all entrances to each station means we want to combine all isochrones for all the entrance points of the same station. This is why we saved the station name for each entrance point. Combining all isochrones for entrances to the same station can be done by selecting the “Merge areas with same value in” checkbox, and selecting “HubName”. “HubName” is the field QGIS used to save the name of the station for each entrance. Calculating isochrones for all entrances takes a lot longer, because we have anything from 1 to 50 entrances to a single station, depending on the station.

For Länsimetro stations, a new feature was added that takes into account walking distance before reaching the entrance point. This is because our Länsimetro points are not located at the station platforms, they are located at the outdoor entrances to the metro station. Länsimetro provided us with a table that allowed us to add walking distances in meters to reach each entrance point separately.

To take into account internal walking distances, you may select the “Add indoor walking distances” checkbox. This allows you to select an integer field that contains the added walking distance at each point in the point layer. Note that this option should not be used with more than one distance division, because it will result in very ugly distance divisions: the distance is subtracted before calculating the isochrone for each point.

1.5 Results

The results look slightly different from the old 2015 isochrones. There are multiple reasons for this: 1) different method of dividing area between roads, 2) more varied speed profile for bicycles, 3) more platform entrances and 4) more paths.

Point 1) means Graphhopper currently divides the area between roads by snapping to any road closest to a point, regardless of distance. This may result in very ugly isochrones in areas where there are no roads, such as woods and lakes. Graphhopper has a number of issues to improve the shape of isochrones by buffering/adding nodes, removing nodes outside the isochrone and adjusting snapping distance for isodistance curves. The latter issue can be addressed in GraphHopper source code by adjusting this row to a value such as 200 or 500 to get less pointed triangles in isodistance curves.

If you are unhappy with isochrones and isodistance curves encroaching into non-accessible areas (water bodies, airports and the like), this is an artefact of the fact that points are mapped to closest walkable node if there is no road network in the area. In this case, you may improve the look of isochrones on non-accessible areas by clipping them with any other polygon layers of your choice.

Here, airport areas and sea and lake masks were obtained from National Land Survey Topographic Database using a QGIS plugin such as NLS Geopackage Downloader and used to clip away clearly unaccessible areas. The same method may be used for any other area types that you consider “unaccessible”; GraphHopper itself knows nothing of areas outside the paths.

Point 2) means Graphhopper has a rather advanced model of estimating bike speeds. Our bike profile varies bike speed from 15 km/h (on paved bike lanes) to much less (on uneven surfaces and forest paths). The speed when walking the bike (e.g. on train platforms) is 4 km/h, and speed on stairs is even lower. This means the bike speeds will be slower than in the old model when the bike is walked or along narrow paths; and the bike speed is highest if there is a paved bike-only lane available. The full code that determines bike speed and route preference can be found in Graphhopper source.

Point 3) means that all paths, elevators, stairs etc. leading to the platforms are included in OSM data, and the points considered are always at the entrance of the platform, not in the middle of the platform. This means there might be more paths available to the platform than in the old data.

Finally, point 4) means that in many cases, OpenStreetMap has a very comprehensive path network mapped by locals, including paths and routes not found in the old datasets. In some cases, such paths may be steep and narrow, and the bike routing takes this into account accordingly by using walking speed on such paths. The only caveat here is the case detailed earlier, where a pedestrian area is only mapped as a polygon in OpenStreetMap. In these cases, paths had to be added to get proper routing across such areas.

5, 10 and 15 minute isochrones by bike to Pukinmäki platform entrances

1.6 License and permissions

These materials are developed for HSY by Gispo Ltd. The materials are licensed under CC BY-ND 4.0 license.