Step 4: Add some colors

In this step, we will prepare and include statistical data and use it to color the municipalities on the map.

Preparation of statistical data

As statistical data, we will use data on municipalities provided by the Swiss Federal Statistical Office. You can download the Excel file and open it, for example using LibreCalc.

Hint

If you want to skip the data preparation steps, you can download the CSV file (right-click, save as ...) from the repository and save it to data/areastatistics.csv. You can then proceed to the section Select some colors.

Unfortunately, the file is not ready to use as such because the file has some metadata and merged column labels at the top. We want it to start right with one row of data labels followed by the data rows.

Also, the file contains a lot of columns which we will not use. In order to keep file size minimal, we are going to delete all unnecessary columns from the file.

For our tutorial, we only need the following columns:
  • Gemeindecode
  • Gemeindename
  • Gesamtfläche in km²
  • Siedlungsfläche in %
  • Landwirtschaftsfläche in %
  • Wald und Gehölze in %
  • Unproduktive Fläche in %

This means you can do the following actions in the Excel file:

  • Delete columns W to AU
  • Delete columns R and T
  • Delete columns C to O
  • We use row 9 as our new header to label the columns:
    • id
    • name
    • area
    • urban
    • agriculture
    • forest
    • unproductive
  • Delete rows 1 to 8
  • Delete rows 2354 to 2367

The table should now look like this:

id name area urban agriculture forest unproductive
1 Aeugst am Albis 7.9 12.6 51.3 30.9 5.2
2 Affoltern am Albis 10.6 30.8 40.1 28.2 0.9
... ... ... ... ... ... ...

We can now export it as CSV document and save it to our data folder as data/areastatistics.csv.

When saving it, make sure to use the following settings:

  • Character set: Unicode (UTF-8)
  • Field delimiter: ,
  • Text delimiter: “”

Select some colors

Next we are going so select some colors for our map. For this, we are using ColorBrewer, which is great at giving color advice for maps.

We choose 9 data classes and select a color scheme that appeals to us, for example YlGnBu. We then click on “Export” and copy the CSS classes for this scheme.

These CSS classes are now pasted in the CSS style section of our HTML document.

style.css - color classes from ColorBrewer
10
11
12
13
14
15
16
17
18
19
20
21
/* ... */

/* Thanks to http://colorbrewer2.org/ */
.YlGnBu .q0-9{fill:rgb(255,255,217)}
.YlGnBu .q1-9{fill:rgb(237,248,177)}
.YlGnBu .q2-9{fill:rgb(199,233,180)}
.YlGnBu .q3-9{fill:rgb(127,205,187)}
.YlGnBu .q4-9{fill:rgb(65,182,196)}
.YlGnBu .q5-9{fill:rgb(29,145,192)}
.YlGnBu .q6-9{fill:rgb(34,94,168)}
.YlGnBu .q7-9{fill:rgb(37,52,148)}
.YlGnBu .q8-9{fill:rgb(8,29,88)}

Color the municipalities by attribute

We have selected 9 classes from ColorBrewer so we want to split the attribute values into 9 categories. Each feature then receives a CSS class based on the category of its value and the CSS class will determine its color on the map.

To achieve the categorization, we create a quantize scale with D3. It creates a number of classes within a given domain and we use it to return the class name used by ColorBrewer.

At the same time, we prepare a D3 mapping object called dataById which will later permit easy access to the data we are about to read. More on that later.

map.js - object to access data and quantize scale
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// ...

// We prepare an object to later have easier access to the data.
var dataById = d3.map();

// We create a quantize scale to categorize the values in 9 groups.
// The domain is static and has a maximum of 100 (based on the
// assumption that no value can be larger than 100%).
// The scale returns text values which can be used for the color CSS
// classes (q0-9, q1-9 ... q8-9)
var quantize = d3.scale.quantize()
    .domain([0, 100])
    .range(d3.range(9).map(function(i) { return 'q' + i + '-9'; }));

// ...

Since the class of the feature depends on the category of the attribute, we need to wait until the CSV is loaded until we can draw the features on the map.

We will load the CSV (using d3.csv()) inside the function called after loading the GeoJSON. The drawing of the features will now happen inside the function called after the CSV is available, meaning that we replace the existing function and move it inside the d3.csv() function.

map.js - load csv and draw the features
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// ...

  // Read the data for the cartogram
  d3.csv('data/areastatistics.csv', function(data) {

    // This maps the data of the CSV so it can be easily accessed by
    // the ID of the municipality, for example: dataById[2196]
    dataById = d3.nest()
      .key(function(d) { return d.id; })
      .rollup(function(d) { return d[0]; })
      .map(data);

    // We add a <g> element to the SVG element and give it a class to
    // style it later. We also add a class name for Colorbrewer.
    svg.append('g')
        .attr('class', 'features YlGnBu')
      // D3 wants us to select the (non-existing) path objects first ...
      .selectAll('path')
        // ... and then enter the data. For each feature, a <path>
        // element is added.
        .data(features.features)
      .enter().append('path')
        .attr('class', function(d) {
          // Use the quantized value for the class
          return quantize(dataById[d.properties.GMDNR].urban);
        })
        // As "d" attribute, we set the path of the feature.
        .attr('d', path);

  });

// ...

Play around

You can try and change the key of the map which is visualized on the map. You can do this by changing the key accessed by the dataById object called inside the quantize() function.

map.js - change map key
64
65
66
67
68
69
70
71
        // ...

        .attr('class', function(d) {
          // Use the quantized value for the class
          return quantize(dataById[d.properties.GMDNR].urban);
        })

        // ...

Try to set it to agriculture, forest or unproductive and refresh the map.

Next

Proceed to Step 5: Dynamic color domain.