D3.js

De Amsterdamse fietser gevisualiseerd

Fietsstad Amsterdam, een nieuw boek van Fred Feddes en Marjolein de Lange, beschrijft hoe Amsterdam een fietsbeleid ontwikkelde (meer over het boek hieronder). Het archief van de Fietsersbond Amsterdam vormde een belangrijke bron voor het boek. Daarnaast is gebruik gemaakt van verkeersgegevens om trends te analyseren.

Een interessante dataset bestaat uit tellingen van het aantal fietsers, auto’s en andere weggebruikers die de stad in- en uitreden, over de periode 1980–2009. De meeste lokaties waar verkeer is geteld liggen op de Singelgracht, die een soort cirkel vormt om het centrum van Amsterdam.

De cijfers zijn telkens gebaseerd op handmatige tellingen op één dag, van 7:00 - 19:00 uur, van het verkeer in beide richtingen.

Ik werd gevraagd om mee te denken over een manier om deze gegevens te visualiseren, een interessante (en erg leuke) klus. Hieronder bespreek ik enkele opties die we hebben overwogen.

Spindiagram

Vanwege de ligging van de tellokaties lag het voor de hand om een cirkelvormige grafiek uit te proberen. De gemeentelijke Dienst Infrastructuur Verkeer en Vervoer was in 2007 ook al op dat idee gekomen. In een factsheet gebruikten ze een spindiagram om de fietstellingen in beeld te brengen.

Overigens noemden ze hun grafiek geen spindiagram, maar waaier. Met een fietsmetafoor legden ze uit hoe de grafiek werkt: «vanuit het middelpunt zijn de telpunten rond de binnenstad verbonden als spaken in een fietswiel».

Het is een mooie grafiek, maar dit grafiektype heeft ook een nadeel. Impliciet wordt de suggestie gewekt dat de oppervlakte binnen de paarse lijn correspondeert met het aantal passeringen, wat eigenlijk misleidend is (zie dit artikel voor een bespreking van een vergelijkbaar probleem). Een andere beperking is dat de grafiek niet laat zien hoe het fietsgebruik is veranderd - al zou je een versie kunnen maken met aparte lijnen voor 1980 en 2009.

Radial lollipop chart

Als alternatief heb ik een radial lollipop chart gemaakt. Althans, zo noem ik hem maar; voor zover ik weet bestond dit grafiektype nog niet. De grafiekbibliotheek die ik gebruik, D3.js, lijkt geen methode te hebben om de ‘spaken’ te tekenen, of in ieder geval kon ik die niet vinden. Ik heb daarom een functie geschreven om het begin- en eindpunt van de lijnen te berekenen. Ik was allang vergeten hoe je sinus en cosinus gebruikt, dus dat moest ik opzoeken. Ik heb de code hier gepubliceerd.

Hieronder een radial lollipop chart die laat zien hoe het fietsverkeer op bijna alle Singelgrachtkruisingen is toegenomen.

En hier een die het tegenovergestelde effect laat zien voor auto’s.

Ik hou er wel van als datapunten buiten het grafiekgebied vallen - al is dit misschien een beetje overdreven. De uitschieters worden veroorzaakt door het feit dat een groot deel van het autoverkeer de route Wibautstraat - IJtunnel gebruikt. Ik had de schaal kunnen aanpassen zodat deze uitschieters binnen het grafiekgebied zouden vallen, maar dan zou het veel moeilijker worden om veranderingen op andere routes en op de fietsgrafiek te onderscheiden.

Vlakdiagram

Ik ben op zich wel gecharmeerd van die radial lollipop chart, maar hij heeft een beperking: hij laat de veranderingen tussen 1980 en 2009 zien, maar niet wanneer die veranderingen zich voordeden. Het autoverkeer nam al af voordat de groei van het fietsverkeer goed op gang kwam, maar op de radial lollipop chart zie je dat niet.

In het boek staat daarom een vlakdiagram, waarbij kleuren corresponderen met de geografische oriëntatie van de kruisingen. Eenvoudig, maar effectief. En als je in de details wil duiken, klik dan hier voor een eerdere schets: fiets, auto.

Over het boek en de tentoonstelling

De Fietsersbond Amsterdam heeft zijn archief overgedragen aan het Stadsarchief. Marjolein de Lange, die een vrijwilligersproject coördineerde om de overdracht voor te bereiden, kwam op het idee om het materiaal te gebruiken als input voor een boek. Dat idee heeft ze vervolgens uitgevoerd samen met auteur Fred Feddes.

Het resultaat is een erg interessant boek over activisme versus samenwerking, over de plek van de fiets in het gemeentelijk beleid en over hoe de toverkracht van de Amsterdamse fietscultuur de doorslag gaf in de epische strijd om de onderdoorgang voor fietsers onder het Rijksmuseum. Verder staat het boek vol fantastische foto’s, kaarten en affiches. Een must voor iedereen die geïnteresseerd is in fietsen, Amsterdam, of actieposters. Er is ook een gratis toegankelijke tentoonstelling in het Stadsarchief (tot 30 juni).

Visualising Amsterdam’s cyclists

Bike City Amsterdam, a new book by Fred Feddes and Marjolein de Lange, recounts how Amsterdam developed a cycling policy (more on the book below). An important source for the book is the archive of the Amsterdam branch of cyclists’ organisation Fietsersbond. In addition, traffic data was used to analyse trends.

An interesting dataset consists of counts of the number of cyclists, cars and other road users moving into and out of Amsterdam’s city centre, over the years 1980–2009. Most of the locations where traffic was counted are on the Singelgracht, which encircles Amsterdam’s city centre.

The data represents manual counts on a single day, between 7am and 7pm, of traffic in both directions.

I was asked to think about a way to visualise this dataset, which posed an interesting challenge (and was a lot of fun to do). Below, I’ll discuss a few of the options we considered.

Radar chart

Given the geographical distribution of counting locations, it seemed to make sense to try a circular chart design. In fact, that idea had also occurred to the city’s infrastructure department. In a 2007 fact sheet, they used a radar chart (or cobweb chart) to visualise the Singelgracht bicycle counts.

Incidentally, they didn’t use the term radar chart, but called it a fan (waaier). They used a bicycle metaphor to describe how it works: «from the middle, the counting locations around the city centre are connected like spokes in a bicycle wheel».

The chart looks really nice, but this chart type also has a drawback: there’s an implicit suggestion that the area within the purple line represents the number of crossings, which is in fact misleading (see this article for a discussion of a similar problem). Another limitation is that the chart doesn’t show how bicycle traffic changed - although it would be possible to make a version with separate lines representing 1980 and 2009.

Radial lollipop chart

As an alternative, I created what I’ll call a radial lollipop chart (to my knowledge, this chart type didn’t exist yet). The chart library that I use, D3.js, doesn’t seem to have a method to draw the ‘spokes’, or at least I couldn’t find it. Therefore, I wrote a function that calculates the start and end points of the lines. I had long forgotten how to use sine and cosine, so I had to look that up. I’ve published the code here.

Here’s a radial lollipop chart showing how cycling has increased at virtually all the Singelgracht crossings.

And here’s one showing the opposite effect for cars:

I love it when a chart has data points that break out of the chart area - although this is perhaps a bit extreme. The outliers are due to the fact that a large share of car traffic uses the Wibautstraat - IJtunnel route. I could have changed the scale to include those outliers, but then changes on other routes as well as changes in bicycle use would have become much more difficult to discern.

Area chart

I rather like the radial lollipop chart, but it has a limitation: it shows changes between 1980 and 2009, but not when those changes happened. Car use started to go down before cycling really started to increase, but from the radial lollipop chart you couldn’t tell.

This is why the chart used in the book is an area chart, with colours corresponding to the broad geographical orientation of the crossings. Simple, but effective. And if you want to explore the details, click here for a draft version of the charts: bicycle, car.

About the book and exhibition

On 4 April, the Amsterdam branch of cyclists’ organisation Fietsersbond has handed over its archive to the Municipal Archive. Marjolein de Lange, who coordinated a volunteer project to prepare the archive, came up with the idea to use the material as input for a book - a project she carried out with author Fred Feddes.

This resulted in a very interesting book about activism versus cooperation; the place of cycling in urban planning; and how the magic power of Amsterdam’s cycling culture decided the epic fight for the right to cycle through the passage under the Rijksmuseum. The book, which contains a wealth of great photos; maps and posters, is a must-read for anyone interested in cycling, Amsterdam, or activist poster design. It’s been published both in Dutch and in English. There’s also an exhibition at the Municipal Archive (until 30 June, Vijzelstraat 32, access is free).

Using a jagged baseline to indicate a broken y-axis

In an article for the recently created Data Visualisation Society, R.J. Andrews suggests using a jagged baseline to indicate a broken y-axis (i.e., an axis that doesn’t start at zero). The idea - inspired by some beautiful charts dating back to WWI - is to suggest that the bottom part of the chart has been torn off. I like the idea - but I found it isn’t easy to implement.

Contrary to the view of some chart fundamentalists, using a y-axis that doesn’t start at zero can be perfectly ok in some situations. Still, one might want to alert the reader that the zero line is missing. One way is to add a little zigzag or some other symbol to the y-axis, as shown here. And then there’s Andrews’ suggestion to use a jagged baseline.

I tried to implement this in a chart that shows the number of flights at Schiphol Airport. For background: Schiphol has all but reached the cap of 500,000 flights per year, agreed on after negotiations between local residents and the aviation industry. There’s currently a heated debate on whether Schiphol should be allowed to grow further. Experts expect that maintaining the cap will result in more efficient use of the available slots (e.g. fewer short-distance flights, fewer low-cost flights, larger aircraft and fewer empty seats).

Creating a jagged baseline is a bit of a hassle: you have to remove the regular baseline, move the axis labels down a bit and create a new, jagged baseline.

And then there are some design issues. Having the baseline and the ‘regular’ chart lines look too similar may cause confusion. In fact, all of Andrews’ examples have very pronounced chart lines, which are clearly distinct from the baseline. If you prefer a more subtle approach, another solution is to use a light colour for the baseline.

Then again, it also matters whether there are gridlines. After some experimenting, I think the jagged baseline only works well with gridlines added; without them it looks a little weird. But see for yourself if you agree.

I’ve written a Python script to download and clean Schiphol Airport traffic data; find it on Github.

How to make a d3js force layout stay within the chart area - even with multiple components

For a post on analysing networks of corporate control, I wanted to create some network graphs with d3.js. The new edition of Scott Murray’s great book on d3.js, which is updated to version 4, contains a good example to get you started. However, I was still struggling with some practical issues, as the chart below illustrates (reload the page to see the problem develop).

A large part of the graph drifts out of the chart area, and the problem only gets worse on a mobile screen. But I figured out some sort of solution.

As Murray explains, you can vary the strength value of the force layout. Positive values attract, negative values repel. The default value is –30. You could set d3.forceManyBody().strength(-3) to create a more compact graph.

Of course, the ideal setting will depend on screen size. You could vary the strength value according to screen width. While you’re at it, you may also want to vary the radius of nodes and the stroke-width of edges. For example with something like this:

if(w > 380){
    var strength = -3;
    var r = 3;
    var sw = 0.3;
}
else{
    var strength = -1;
    var r = 3;
    var sw = 0.15;
}

Now this may make the graph more compact, but it doesn’t solve one specific problem: components not connected to the rest of the chart will still drift out of the chart area. In my example, there are four components: a large one, and three pairs of nodes that are only connected to each other and not to the rest of the graph.

The way in which I dealt with this was to create four different graphs and attach the small components to a forceCenter at the margin of the chart area. For example, d3.forceCenter().x(0.1 * w).y(0.9 * h)) will put one of them in the bottom left corner. Here’s the result:

It’s still a lot of code - I can’t help feeling there should be a more efficient way to do this. Also, it’s slightly weird that the small components immediately freeze, whereas the large one takes its time to develop into its final shape. And the text labels could be improved. But at least it seems to work.

Embedding D3.js charts in a responsive website - a better solution

I often use D3.js to create charts which I embed on my website (the chart below is included merely as an illustration; it was copied from here). Normally you set the width and height of the embedded page in the embed code, but with a responsive layout it’s not so simple. The challenge is to adapt the iframe width to varying screen sizes and change the height so that the chart still fits.

After struggling with this issue for quite a while I thought I had come across the solution and wrote an article about it. However, this solution has two problems:

  • You have to define the aspect ratio in both the embed code and the D3 code; ideally, you shouldn’t have to do that in more than one place;
  • More importantly, it doesn’t take the height into account of any title and captions that are not part of the D3-created svg. You could handle this by making the title and caption part of the svg itself, but this is a bit awkward, especially with multiline captions.

A while ago, I came across a different approach which uses HTML5’s postMessage. The embedded page posts a message containing it’s own height to the parent page. The parent page picks up the message and changes the iframe height accordingly.

A smart variant has the embedded page not only send its height, but also its url to the parent page. That way, you can identify the corresponding iframe by its src attribute and thus make sure the right iframe gets updated - which is nice if you have more than one iframe on a web page.

Here’s how it works. In the D3 code, set the width of the chart to the width of the div the svg is attached to and use the aspect ratio to calculate the chart height. Also add the following code to the embedded page. It will send its height and url to the parent page:

function sendHeight() {
  var height = $('body').height();
  window.parent.postMessage({
    'height': height,
    'location': window.location.href
  }, "*");
}
 
$(window).on('resize', function() {
  sendHeight();
}).resize();

And here’s the code for the parent page. It will pick up the message, identify the corresponding iframe and update its height (note that Drupal requires jQuery instead of $):

window.addEventListener('message', function(event) {
    if (event.origin !== 'https://dirkmjk.nl') return;
    var data = event.data;
    var height = data.height + 32;
    jQuery('iframe[src^="' + data.location + '"]').css('height', height + 'px');
}, false);

In the second line, the domain should be replaced with the domain where the embedded page is hosted (the line checks for the origin of the posted message for security reasons).

I haven’t extensively checked this but it works on iOS and Android. Since it uses postMessage, it will not work on some older browsers. Then again, D3.js won’t work on some older browsers either.

Credits go to thomax and Jan Werkhoven.

Pages