Empty Pipes

D3.js and Contouring

  • 22 Jul 2015
  • |
  • javascript
  • d3.js
  • |

Contouring is an important way for displying 3D data in 2D. At its core are iso-lines, along which values in the third-dimension have equal values, and iso-bands which are areas that encompasse values within some range (e.g. greater than 2 and less than 10). It is used for anything from topographical maps to show lines of equal elevation, weather maps to show regions of equal pressure to probability density plots to show regions with equal probability density. Calculating iso-lines and iso-bands is often done by interpolating values on a grid.

From a practical standpoint, there appear to be 3 javascript libraries capable of calculating iso-lines and iso-bands, MarchingSquares.js, conrec.js and Turf.js. The table below shows an overview of the three different implementations and is followed by a slightly more thorough explanation of their strengths and weaknesses.



Pros: Simple. Adds contours to the edges of the data. True iso-band support.

Pros: Options for specifying x- and y- values. Pros: Interpolates the input data. Works with GeoJSON data structures.
Cons: Works only on gridded data. No option for specifying x- and y- values. Cons: Works only on gridded data. Doesn't return true iso-bands. Requires a extra values to draw a border. Cons: Interpolates the input data (can cause distortions). Works with GeoJSON data structures. Doesn't return actual iso-bands.

MarchingSquares.js uses the eponymous algorithm to calculate both iso-lines and iso-bands. Conrec.js uses a slightly different algorithm and returns iso-lines, whereas Turf.js appears to use the conrec algorithm to generate iso-lines. The examples above used the following data set. The breaks indicates where we want the iso-lines, and the iso-regions should correspond to areas between adjacent breaks.

    var breaks = [0, 4.5, 9, 13.5, 18];
    var data = [[18, 13, 10, 9, 10, 13, 18],
        [13, 8, 5, 4, 5, 8, 13],
        [10, 5, 2, 1, 2, 5, 10],
        [9, 4, 1, 12, 1, 4, 9],
        [10, 5, 2, 1, 2, 5, 10],
        [13, 8, 5, 4, 5, 8, 13],
        [18, 13, 10, 9, 10, 13, 18],
        [18, 13, 10, 9, 10, 13, 18]];

MarchingSquares.js accurately returns is iso-bands and draws the plot as expected. Each path corresponds to a particular region. Thus hovering over the middle section also highlights the outer section which corresponds to the same values (13.5 - 18).

Conrec.js correctly outlines the regions, but the level returned for the second and third sections from the middle is the same although they should correspond to different iso-bands. To create the plot, it was also necessary to add some artifically high values along the outside boundaries so that iso-lines were drawn around the edges.

Turf.js interpolated the data onto another grid and drew iso-lines in the same manner as conrec.js. The automatic interpolation is listed in the table as both a pro and a con because it can be useful when the data is not already on a grid, but deleterious when it insists on using a uniform resolution on both the x and y scales and re-interpolating already gridded data (as in the example above).

Needless to say, of the three methods, MarchingSquares.js was the easiest and most aesthetically pleasing to me so I will likely use it in the future.

The code for all three of these examples can be found in a github repository here.

If you see any errors or omissions or know of a way to make the Turf.js example look more reasonable, please let me know on Twitter or by email.

Approximate Flight Time Map

  • 13 Jul 2015
  • |
  • javascript
  • d3.js
  • maps
  • |

The map below shows the approximate flight time (in hours) from any location on earth to any other.

  • Double click to change the starting point (sorry mobile users!).
  • Click and drag to pan
  • Scroll to zoom in and out
  • Click on the Flight Times and Flight Paths checkboxes to toggle the displayed lines

  • The red lines above indicate equal distances of approximately 1660 km, from the starting location. This distance corresponds to (very) roughly two hours of flight time in a commercial airliner. The actual time would depend on the type of plane, wind conditions, trajectory and a host of other factors that are omitted for simplicity.

    The flight paths option, when checked, shows the path a flight might take when going to any point on the globe. Notice that no matter which direction it goes in, it will always go over the opposite side of the earth if it flies long enough.

    The more observant of the viewers will notice that the distances and paths above are equivalent to rotated latitudes and longitudes where the ‘topmost’ point is not the north pole, but rather the location chosen as the starting point. If there is a proper name for these rotated meridians and parallels please let me know.


    Is it further to fly from Madrid to Los Angeles or from Helsinki to Los Angeles? Think about it. If you’re anything like me, you would have guessed Madrid, and you would have been wrong. Madrid is about 9300 km from LA, while Helsinki is 9000 km, as the plane flies.

    What gives? Well, essentially the earth is a sphere (mostly), and the map is distorted. A plane flying from Helsinki to LA would actually start off flying north-west rather than south-west (where LA appears to be), because it would be flying along the great circle which contains both LA and Helsinki (or Madrid). Because the flight goes over the ‘top’ of the world, it’s actually slightly shorter than the flight from Madrid, that has to go around nearer to the equator.

    Other interesting facts that one can glean from this map:

    • New Zealand is opposite Madrid on the globe.
    • Ecuador and Colombia are opposite Indonesia
    • If you wanted to fly direct from New York to Jakarta, you would have to go either directly north or directly south
    • It would take a commercial airliner about 22 hours to fly halfway around the globe.


    Thanks to patricksurry’s block for an example of how to implement a rolling pan and zoom with d3.js.

    Errata / Disclaimer
    Everything is an estimate. Rounding errors abound. Don’t use this for anything but entertainment and curiosity. But you already know that.

    Isochrone Maps of Europe

    • 20 May 2015
    • |
    • maps
    • javascript
    • d3.js
    • leaflet
    • |

    Edit: Any time you see ‘train’ below, it should technically be public transport. The vast vast majority of the travel used to make these maps is by train, but a very small percentage may involve ferries or buses.

    Below is a map showing how long one would expect to travel to any point in Europe starting in Vienna, using only trains and walking at a brisk rate of 5 min / kilometer.

    Other Cities

    Amsterdam Antwerp Barcelona Belgrade
    Berlin Birmingham Bratislava Brussels
    Bucharest Budapest Copenhagen Dublin
    Frankfurt Geneva Helsinki Jena
    Ljubljana London Madrid Minsk
    Oslo Paris Podgorica Prague
    Riga Rome Sofia Stockholm
    Tallinn Vienna Vilnius Warsaw
    Zagreb Zurich

    Errata / Disclaimer
    Everything is an estimate. Rounding errors abound. Don’t use this for anything but entertainment and curiosity. But you already know that.

    Some data may be missing. There may be faster connections. If you find issues, please let me know and I’ll do my best to fix them. Thanks to cuicuit on reddit and @yorksranter for pointing out missing data for Paris and London! This data has been added.

    Ireland and parts of Spain are not well represented due to missing data.

    How it’s made, technically

    I used the Swiss public transport API to get travel times to most other small-medium sized cities in Europe. Then I created a rectangle enclosing most of Europe (the borders of which can be seen in the maps for Stockholm, Helsinki and some of the Baltic countries), and divided it into a grid (200 x 200 points). For each point in this grid, I calculated the fastest way to get to it assuming that the distance between the any train station and that point can be walked at a rate of 5 minutes / kilometer. Any points on water were assigned a swimming rate of 100 minutes / kilometer in order to create dense contours at the coasts.

    This grid was used as an input to conrec.js which created a set of contour lines. These lines were then plotted as a paths using d3.js on top of a leaflet.js layer using the Stamen maps tiles. These tiles were chosen because they provide tile sets containing the borders and labels which can be overlayed on top of the colored contour plot.

    The legend is its own div positioned directly below the map. The color map is cubehelix, which provides a nice range from dark to light tones while providing intermediate colors to distinguish the different contours.

    Background Information and Motivation

    While browsing twitter, I recently came across this wonderful isochrone map of the travel times by train from Vienna to the surrounding region at the turn of the century. As happy resident of Vienna, an avowed admirer of trains, and an ardent afficionado of maps, that map strikes a strong chord with me not only for its historic cachet but for its clean design and aesthetic appeal. It conjured images of steam trains (were the trains in 1900 still running on steam?) chugging along between the imperial centers of Vienna and Budapest. It made me wonder about how people commuted from the train station to their final destination. It made me question my conception of how long it took to get from place to place. Most of all, however, it made me wonder what such a map would look like today.

    Having toyed with the idea of plotting travel times by train in a previous post, the map at Alternative Transport, along with Beau Gunderson’s route times in Seattle, made me realize that contour lines are a much better way of presenting the information. Relying on shades of a color makes it difficult to distinguish difference between disparate points on the map as well as to convert to an absolute value. Questions such as “how much darker is point A than point B?” and “what actual time does a particular shade correspond to?” are resolved using the interactive maps (i.e. Vienna, Paris, London, Berlin), but these fail to provide the information at a mere glance. A map containing contour lines corresponding to the locations which can be reached in a particular amount of time provides a clear and concise comparison between the travel times to various locations as well as a concrete reference to the absolute time required to reach a particular point. An example of such a map, called an isochrone map, is provided for Vienna above.