The entire HTML file to generate that is 59 lines. And the code is very simple, too.
The OpenData initiative has resulted in a lot of cool publicly available data in Switzerland. The portal for it is opendata.admin.ch, which is where I found this CSV file containing tax rates in the canton of Zurich from 1990 to 2014.
For drawing a map, d3.js supports GeoJSON, a relatively simple format for map geometry. But an extension of this called TopoJSON is even more popular, because it can re-use shared line-segments on borders and thus results in smaller files.
For this project, I need a map of the municipalities in the canton of Zurich. Apparently, map data is available from swisstopo for free, but I couldn't really figure out what data I need and how to get it in the right format. Instead I found this cool GitHub repository, which contains all sorts of maps for Switzerland, readily available in TopoJSON format. Here's how I got my map data:
Setting up d3.js
Now that we have, we need a web server. The reason for this is that we want to load data from outside of the website, but for security reasons we can't just load file:// URLs from JS. If you have Python 3 installed, the simplest way to start a web server in the current directory is with the command
Now, let's fill that index.html with a basic JS playground structure. We're going to load two external JS libraries: d3.js and topojson to convert our TopoJSON into GeoJSON.
Here's the basic skeleton:
Drawing the map
Let's load the TopoJSON file first. d3.js has a very nice way to load and parse JSON files.
The second step isn't quite as nice, it's time to convert it to GeoJSON to make it d3.js-compatible. For this, we use the following line:
The next step is to turn these coordinates into paths. Right now, it's not really defined what these coordinates mean. Are they like latitude and longitude - do we need to deal with projections and angles and all that stuff? Luckily no, to quote the map repository:
Next thing, we add a canvas to draw the map on. SVG inside HTML is cool because you can style the elements with CSS. Let's create a SVG tag, and style it with the 960×500 pixel size.
Here is a link to the source code so far.
Coloring by data
For the next step, we would like to colour the municipalities by tax rate. This means that we're going to access two data sources at once, the TopoJSON file and the CSV containing the tax data. We can use d3.json and d3.csv to load both files separately, then call a function in both that checks whether both files have been loaded or just one, and if both, execute main. However, there's a much nicer implementation that scales to an arbitrary number of datasources: queue.js. queue.js is embedded just like the other JS files:
Now we convert this into a linear color scale ranging from some green value for low taxes to some red value for high taxes. Here's how it's done in d3.js:
But wait, how does that magic data() call know which entry in the taxes list corresponds to which municipality? The answer is: It doesn't. It just happens to be the case that both lists, the GeoJSON and the CSV, are sorted by BFS ID, which is the unique ID for municipalities. Per default, d3.js just maps the nth data element in the array to the nth HTML element. If our list were not sorted, we'd either have to do that or supply a second argument to data() to sort out the mapping between data points and HTML elements. Finally, lakes have the highest IDs, so they ended up as the last elements. So it doesn't matter that they don't exist in the tax data. Lucky us! So how do we color the lakes blue? Remember how I talked about enter(), exit() and update selections? In this case, we update our data with tax data, and the lakes don't have any tax data. Therefore, they end up in the exit() section. And here's how we can modify our code to color them, too:
Here's a link to the finished HTML file. Take a look at the source code to make sure I'm not cheating.
If you want to find out more about map drawing in d3, there's a nice tutorial called Let's Make a Map by Mike Bostock, king of visualizations and writer of d3.js.
Confused by what those data() and enter() calls do? Take a look at Thinking with Joins by the same guy. Finally, there's always the d3.js API Reference for all the details.
I'm sure you can come up with many more interesting maps and visualizations. If you've made a cool one, shoot me an e-mail!