An Intro to Isochrones with Targomo’s Isochrone API
By: Gideon Cohen
Tags: Geospatial, Targomo, Isochrones

Introduction

Targomo offers a large suite of GeoSpatial tools that can be used to perform powerful location-based analysis, provide detailed statistics visualizations, and solve complex logistical problems. Today, however, we will be focusing on one of the simplest yet most useful APIs; The Isochrone API. The Isochrone API is used to visualize reachable areas from a source or group of sources as GeoJSON polygons. This can be used in a variety of useful applications but I will focus on 3 areas in this article to get you started.

Simple Polygon Reachability Multi-Source Polygons and Polygon Intersections Filtering targets using Polygons

All Isochrone examples in this article were produced using a ‘Pay per use’ Targomo API key with requests sent to publicly accessible endpoints. While this is a “paid” key that requires a valid credit card to register, you are allocated €300 worth of free operations per month (which is around 200,000 operations for the Isochrone API for requests up to 1h max range bands). The background maps shown were made using a free MapTiler account API key as well.

This article will use the core JavaScript Library to handle requests and responses from the Targomo Isochrone API but there are several alternatives available if needed. These include the JavaScript Leaflet and Google Maps extensions, the Targomo Java Client Library, or via direct REST request. The complete code for all examples here plus a few extras can be found in this GitHub Repository. For other similar examples and many many more check out the Targomo Developers Code Examples page.

So what is an Isochrone? You can find an in depth explanation here, but they are defined as “An isoline on a map or chart connecting points that have the same value for some time-related variable”. The shapes returned by the Isochrone API represent this by joining all the furthest reachable points on the routing network from the given sources to form a polygon. We refer to these as ‘reachability polygons’ or ‘Isochrones’. The definition is stretched slightly on our end though since we can visualize on both time and travel distance and also offer the capability to define multiple sources and aggregate the resulting isochrones. Throughout the article I will mostly be referring to the returned objects as ‘polygon’s as we will be working with them as we would almost any GeoJSON polygon.

Setup

Tools

Using the Targomo API doesn’t require the use of any complex tools or libraries. Nothing beyond acquiring Targomo and MapTiler API keys is necessary. Everything in this article relies on HTML, CSS and JavaScript so should run fine on almost any browser with any operating system. Nothing special needs to be installed on your computer to run any of the code examples here although I did use Visual Studio Code and the Debugger for Firefox when creating these examples for convenience, but this could just as easily be done in your editor of choice (or even in a basic text editor).

HTML Dependencies

We use a small selection of HTML dependencies for our maps, the targomo core library, and some visual improvements. All major dependencies can also be installed via NPM, only the button icons and micro progress bar (both just used for visual improvements) are specifically just HTML dependencies.

mapbox-gl Is used to display both our map itself and the resulting polygons. turf provides some simple fitting functionality so we automatically focus on the area of the map we are interested in while d3js gives us an easy way to check which targets are contained within an polygon when filtering. Finally the targomo/core library provides a simple interface with the Targomo REST API which will be used to retrieve the polygons we will work with.

Setting up your workspace

First let us set up an index page that will act as the hub to connect to our map examples. Create the following files at the root of your workspace

index.html

polygon.html

polygon-filtering.html

polygon-intersection.html

Now we need to create links to each of those pages from our index. Add the following to index.html

Next we want to create a folder called map-cards and download all the images found here into that folder. Now we want to add these to our index and add some styles. Create a folder called style and inside that folder a file called index.css and add the following.

If you open index.html in a browser you should now have an easily expandable card menu that looks something like this:

A Simple Index Page

Now we have a nice hub page from which to work. Before moving on to creating the actual maps we should talk briefly about the request and response formats we will be using in this article.

As mentioned above I will be using the Targomo JavaScript client library to make requests for all of the following examples. Making requests with this library is very simple. First we need to create a client. The client only needs two parameters, the name of an ‘endpoint’ and your Targomo API Key.

An ‘endpoint’ simply defines the geographical region you are working in. A full list of available endpoints and their coverage areas can be found here but we will be using the westcentraleurope endpoint for all examples here. Once your client is created making the request requires two inputs.

Sources: The sources are an array of JSON objects that define the ID, Latitude and Longitude of coordinates to route from.

Options: The options parameter acts as the body of the request containing the parameters that will define the result. Here is a basic set of options.

More details about these parameters and more can be found in the documentation but I will give a brief overview of the options presented here.

travelType : This is the mode of transportation used. It can be one of walk , car , bike or transit .

: This is the mode of transportation used. It can be one of , , or . edgeWeight : This defines the travel measurements. It can be either time or distance which will cause travel to be calculated in seconds or meters respectively.

: This defines the travel measurements. It can be either or which will cause travel to be calculated in seconds or meters respectively. travelEdgeWeights : This defines the size and number of polygons to calculate. Each number in the array represents an individual polygon that will be returned. For time these are in seconds while for distance these are in meters. In this case we are creating a polygon at 5 minute intervals.

: This defines the size and number of polygons to calculate. Each number in the array represents an individual polygon that will be returned. For these are in seconds while for these are in meters. In this case we are creating a polygon at 5 minute intervals. srid : The 'spatial reference identifier' system for the returned polygons. Currently 4326 and 3857 are supported.

: The 'spatial reference identifier' system for the returned polygons. Currently and are supported. serializer : This is the format of the response data. We also offer a custom compact json serializer for use with our leaflet and Google Maps client libraries but will be focusing on the GeoJSON serializer in this article.

: This is the format of the response data. We also offer a custom compact serializer for use with our leaflet and Google Maps client libraries but will be focusing on the GeoJSON serializer in this article. simplify : This is used to smooth the edges of polygons by reducing the number of points based on the input number (in meters). Points closer than the given number will be removed.

: This is used to smooth the edges of polygons by reducing the number of points based on the input number (in meters). Points closer than the given number will be removed. quadrantSegments : The vertices of the polygons are buffered in a semi-circular fashion, this determines how many segments a 90 degree angle would be translated into. The higher the number, the smoother/more rounded the edges of the polygon. Ranges between from 2 to 8.

: The vertices of the polygons are buffered in a semi-circular fashion, this determines how many segments a 90 degree angle would be translated into. The higher the number, the smoother/more rounded the edges of the polygon. Ranges between from 2 to 8. buffer : This defines and amount in the given srid to widen each polygon by. buffer , quadrantSegments , and simplify can be used in conjunction to make returned polygons both nicer to look at and easier to comprehend.

These parameters, alongside many others, allow for extensive customization in the requests enabling polygons to be created for highly specific use cases. Once you have these two parameters defined you only need to call the polygons.fetch request function.

Responses

The response data is always returned as a JSON object and in the case of the GeoJSON serializer specifically, as a FeatureCollection . Below is an example with 6 bands each at 5 minute intervals. This example and several others can be found here

The response will return a FeatureCollection containing a MultiPolygon for each range band defined in the travelEdgeWeights parameter of the options. This data can be passed directly to other libraries that accept GeoJSON for visualization, such as MapBox GL which we will be using here.

Simple Polygon Reachability

Whether checking areas within a reachable time/distance of a new home by car or analyzing the accessibility of a potential school via public transport, the Isochrone API offers what I hope to demonstrate as a quick, easy and relatively simple solution. For this example we will be using a single source to explore the effects of the different options parameters. Fist let us make an HTML page with all the dependencies we need. Add the following to the polygon.html file.

Not much needed here, just a basic html page with a div to house the map and some dependencies. Now we need to add some simple css to control the map. Create a file in the style folder called maps.css . This will hold the css for all of our map pages going forwards.

We don’t need to add much as the actual visualization will be mostly by MapBox so w simply fit the map to the entire screen. Finally we can get started on the JavaScript. Create a folder called javascript at the root of your workspace and add a file called polygon.js . First let's start by defining everything we need to call the targomo API.

That’s it, The client, a source point, the polygon range bands, and some options. We keep the range bands as a separate variable as we will use them again later to help when visualizing the polygons. Next up we need to create the map itself and define what our polygons will look like.

The empty data will be used to initialize the map while the color array is used to define the colors of the different polygon range bands. The Marker will represent our source point which we want to be ‘draggable’ so we can change the source location. Now we need to actually retrieve the polygons and fill in the map. To do so we will create 3 Utility methods.

getPolygons() is the most important here and will do the bulk of the work, retrieving the polygon and updating the map. It will also recreate the source from the marker each time which is required to update the location of the polygon. getHeightPolygons() and getColorStops() are used by the MapBox layers to extrude and then color the different polygon bands allowing us to differentiate them visually. Polygon heights can be useful visualization tools for 3d maps and can be especially useful when you have enough range bands that separating by color alone becomes cumbersome. Finally it is time to load the map and actually see what this looks like. Don't forget to replace the placeholder API keys with your own.

That’s it, load the HTML up in any browser and you should have a simple biking polygon that look like this.

Simple Reachability Polygon

Now we want to be able to look at polygons for different travel types. To update the travel type we will need to update the options.travelType parameter to one of bike , walk , car or transit and send a new request. Let’s add some travel type buttons. First add the following to the HTML before the script is loaded.

These buttons will use some of the Targomo UX icons and include a tool-tip but the actual contents don’t matter. Now we should add some CSS to help style these buttons.

Finally, we need to add the requisite JavaScript to properly update the buttons when clicked.

We use some extra code for TravelType elements since we will add another set of buttons later to update IntersectionMode . This will be covered more in the next section but for now let's see what our buttons look like and how travel type can affect the polygons.

Isochrone for TravelType Walk

Isochrone for TravelType Bike

Isochrone for TravelType Car

Isochrone for TravelType Transit

In the first row we can see that bike and walk look very similar. Generally all polygons are quite circular with some distortion around the edges as the network radiates outwards at different rates depending on physical factors such as the number of other roads to cross or elevation changes. There are very few places where one can bike but not walk, however a bike is generally faster so we simply see a larger area covered.

Car and transit, on the other hand, are completely different stories. The car polygon bands are, aside from being significantly larger, much more distorted as the cars move on and off highways or into smaller side streets and this creates long stretched reachable lines along major roads. We are also more likely to see holes in the polygons or sudden cutoffs in reachability as we interact with places a car cannot go (such as parks) or infrastructure with limited entrances (for example large stadiums or airports).

Transit polygons create shapes unlike any other travel mode. A mixture of trains, buses, or even simply walking creates pockets of disconnected or overlapping polygons for each band based on the position of transit stops. The separation and distortion of the polygons gets progressively more pronounced the further away from the source. This is also the most time sensitive of the travel types as a difference of only a few minutes can determine whether one can get to a specific bus or train in time to use a specific route. All of these factors and more can be adjusted in the options of the request. This will be covered in more detail further on, but first let’s look at requests with more than one source.

Multi-Source Polygons and Polygon Intersections

Multi-source polygons allow for a much detailed investigation of reachability. Maybe you are looking for amenities reachable from both your home and an office, analyzing the coverage area of location networks (shops, transit stops, public parks, etc) or maybe just finding the easiest place for groups from several locations to meet. We can easily create polygons with more than one source, but how these sources interact with each other depends on the intersectionMode . If not set this defaults to union . I will explain each of the intersection modes later, for now create a new file in the javascript folder called polygon-intersection.js and copy all the code from polygon.js into it. Do the same with polygon.html to create polygon-intersection.html and update it to point towards the correct JavaScript file. Now let's start changing this to deal with multiple sources. For this example I will use 2 sources. First we want to define 2 sets of coordinates and add the intersectionMode parameter to the options

Next we need to create an arrays of both markers and sources from these coordinate pairs. First for the markers we simply need to derive the makers from the coordinates list and add all of them to the map. Replace the assignment of marker with the following.

Now, like before we will use the markers to derive the sources so they update on drag. This time we will create an array of sources to pass to the polygon method but this otherwise the same as before.

Finally add the array of markers to the map where before you added just one.

There you have it, a multi-source polygon that should look something like this.

The union of two reachability polygons.

Here we are using the default intersection mode, union . In this mode all polygons generated will be combined, with the source with the closed range bands having highest priority. This is used to define the closest reachable area from any source , and is useful for figuring what areas are reachable from any of a number of locations such as the coverage area for a collection of store. There are two other intersection modes; average and intersection . As you would imagine, average provides the average reachability from all sources, this is most useful for calculating the "most reachable" area from all your source. This could be used to simply find a convenient meet-up space or to pinpoint the best place for a supply warehouse from a group of retailers. intersection , on the other hand, only shows the area that is reachable from all sources with the longest distance taking precedence over all other values. This could be used, for example, to define an area reachable from both your house and workplace. For both these modes we need to be careful as if any two sources are too far away from each other we could very easily get no polygon returned. We want to be able to switch between these intersection modes so we need to add buttons as we did for travel types. Luckily we can replicate and re-use most of what we did before. First add the HTML and CSS.

To avoid on part of the map being overcrowded with UI elements I placed the intersection mode buttons in the bottom left of the screen so the only CSS we need to add is a few lines to control positioning. For the HTML we have switched to using data-mode instead of data-type and added a new class mode . This will help us differentiate the two button sets in the JavaScript. Now we just need to add the new update methods.

Now you should have another set of buttons to configure the polygons that looks like this.

The union of two intersection polygons with the addition of an interface,

Okay so now let’s look at what intersection and average would look like with these same points.

The intersection of two reachability polygons.

The average of two reachability polygons.

As shown here intersection provides useful insights into the areas reachable (both most reachable as will as reachable at all) from all points. average on the other hand gives us a view of the "most reachable" areas from our given source points. For users looking to perform more advanced aggregations on the reachable areas of a number of points you can also look into using Targomo's Multigraph API.

Filtering using Polygons

When displaying a group of locations to a viewer (maybe a customer, a business associate or just as part of a larger presentation) you may want to filter your target locations based on their reachability to one or more sources. Targomo’s APIs offer several methods that can achieve this, each with their own contextual advantages and disadvantages. The most Travel Time API would probable provide the most precise results for filtering targets as you can filter on and check precise timing, but for this example we will look at how to use polygons to filter target locations. In this example we will be trying to find all houses reachable from a selection of beaches on the Italian cost. This may be useful for those seeking property in the area or maybe just holiday makers finding a place to stay. The same principles used here could also just as easily be applied to, for example, seeing how many outlet stores are in the catchment area of a selection or warehouses.

We will be using some publicly available data for sources and targets and then filter them using one polygon range band. Highly complex filtering can be achieved such as changing display depending on which of a number of range bands the target lands in or dynamically filter targets as they enter or leave a location, but in this case we will be simply be generating a single polygon from a selection of sources and filtering out all targets not contained within the polygon. We will be using d3js to filter the targets as well as a custom targomo progress bar so our dependencies will look a little different for this file. Like before you will need to create two files polygon-filtering.html and javascript/polygon-filtering.js . The polygon-filtering.html is a bit different from the rest and should look something like this.

The display is very simple here and all the ‘filtering’ will be handled by MapBox so we only need to add some small CSS for our range bar.

The range bar will be used so we can adjust the time range of the filtering polygon. We will use a range of 0–1 hour with 1 minute steps. The JavaScript will also be quite different as we will want to dynamically adjust the size of the polygons and recover the sources and targets from a public source. First we want to set up all the variables we will need very just as we did last time.

Much of this is identical to what we have defined before with only a few changes and new additions. The map is made in pretty much the same way before with the center set directly instead of using a source coordinate. Of the two data URLs present we will use the beaches for the sources and the houses as the targets. Lastly the progress bar will be used to show when data is being loaded. Now let’s create the methods we will need to retrieve and process this data. Firstly the source and target data needs to be retrieved.

Here we create the sources and targets differently since we need sources for the polygon request while the targets will be used by the map. We add a property contained for the targets which will be used to flag those that are within the generated polygons. The polygon request itself remains mostly unchanged from the multi-source requests. In this case we make the source list beforehand and we expect them to be both static in position and number so we don't need to dynamically create or update them like in previous examples. Finally we actually want to perform the filtering.

As shown here we used the polygon from the response alongside the geoContains method from d3js to check for contained coordinates and update the value of the contained property accordingly. Once done all we need to do is update the sources (to keep them above the polygon when displayed on the map) and targets, then hide the progress bar to indicate we're done. Similar to the buttons from the other examples, the filter can be used to update the display except this time we update the travelTimes of the polygon rather than the travelType . Finally we just need to create the map. This will be a bit more complicated as we have a few more layers to handle this time.

Here the map has 4 layers. One each for the polygons and sources while two layers for targets so we can differentiate reachable and unreachable targets. In actual use cases (such as housing/office searches) you may want to simple exclude polygons and unreachable locations from the map to present a more clean and understandable view. Here I have kept each layer to better represent what is actually happening. Now that it’s done let’s take a look at the filtering our filter map for 15, 30 and 45 minutes.

Filter all houses more than 15 minutes away.

Filter all houses more than 30 minutes away

Filter all houses more than 45 minutes away

Advanced Isochrone Usage

With the three examples above I hope to have given a good starting point to begin using Targomo’s Isochrone API to visualize and investigate location reachability. Before we conclude I wanted to take a moment to briefly talk about some of the more advanced control offered when analyzing reachability that didn’t quite fit in any of the above sections.

For each travel type (car, walk, bike and transit) there are a number of factors that can dramatically alter the travel time and can be used to fine tune your requests when examining very specific scenarios. The most in depth explanations and documentation can all be found in the REST documentation. Direct requests can be used instead of the JavaScript library and, although they lacks some of the conveniences, are useful if you need more precise or in-depth control than the library allows.

When traveling by car, the presence of traffic lights or intersections can make a significant different to a journey. when traveling by car 4 options ( trafficJunctionPenalty , trafficSignalPenalty , trafficLeftTurnPenalty and trafficRightTurnPenalty ) can each be specified and tweaked to your own specifications allowing for more contextually accurate analysis for drivers inside and outside cities or across countries. These can be combined with travelTimeFactors , a list of adjustment factors that can be used to modify speeds listed edge types (e.g. a 50% reduction in time for highways, penalties for small side roads, etc), to give extremely granular control over road movement speeds.

For bike and car, which also allow the above penalties to be specified, users may find that their own travel speed (and thus time to location) is vastly different from that used by default in the API. While these are assumed by default as 15km/h for bike and 5km/h for walk, you can adjust these values to match personal travel speeds. You can also add ‘penalty’ modifiers to affect moving up/downhill. The Uphill penalty specifies how much a distance is increase per one meter increase in elevation thus, an uphill penalty of 20 means that per one meter increase in elevation the distance is increased by 20 meters. Downhill is the same so if you wish to reduce the distance you can use a negative modifier.

Transit probably offers the most in depth control, including transfer limits, max distance from source/target, and frame duration. Probably the most obvious control required for public transit of any kind is time and date. For the Targomo APIs this is handled by transitFrameDate and transitFrameTime respectively. Both take in integers with date using a YYYYMMDD format (so the 1st of June 2021 would be 20210601 ) while time can be specified as number of seconds past midnight (3am would be 10800 , 10am is 36000 , 14:30 is 52200 and so on).

Beyond Isochrones

The examples I have provided above are by no means a comprehensive list of everything the Isochrone API, let alone the entire Targomo API suite, is capable of. We offer several other APIs each of which, as mentioned briefly in the filtering section, has its own advantages and disadvantages. Probably the most obvious is the lack of detail. Yes a target may be within the polygon but exact details on how to get there or precise travel times/distances are missing. For a further look at these I encourage you to check out the Targomo Travel Time or Route APIs. You can also look at how reachability can be used in Targomo’s more powerful APIs. Qualitative location evaluation from the Statistics or Point of Interest APIs, precise network aggregation and analysis via the Multigraph API or advanced logistical constraint solving using the Fleet API.

For a look at a much more advanced version of the examples displayed here and much more I encourage you to check out this Demo App as it can provide examples for single and multi-source polygons as well as sources to targets routing.

Conclusion

Targomo Offers a powerful and flexible GeoSpatial tool with the Isochrone API. The generated polygons can be easily integrated into map displays create an easy to understand visualizations for end users. This can help with a number of use-cases such as analyzing the reachable area of a new home, finding the most reachable location for a new office, or determining if the catchment area of a single warehouse covers all target locations. Hopefully the example I have provided allow you to start creating your own mapping tools. You can grab your own Targomo API key and start trying out these examples for yourself. I hope you adapt and expand on the examples here to explore more potential use cases and create visualization tools, search filters and more.