Using the D3 JavaScript Library
for Interactive Graphs and Maps

A Bar Chart of Population Data

In this section we will make a more elaborate data-based visualisation: A bar chart of the population of the municipalities of Overijssel province. We will start by looking at some D3 code that creates a simple bar chart from data that is included in the code, in the same way you did in the previous section.

The page in the figure above is made by the code in Listing 8. Study the code carefully, try to understand how it works: How the data is used to set the position of the bars, their width, and so on...

Some elements we have not seen before are:

  • the code at the top (in the <style> tag). This is using the CSS or Cascading Style Sheets language. We will not go into details on CSS in this exercise, suffice to say that it sets the styling of the elements of the chart class, which is the CSS class used in creating the svg element in line 23.
  • the append("g") and append("rect") methods in lines 35 and 38; These, not surprisingly, create g and rect elements, i.e. groups and rectangles, in the same way we created circles earlier; We use a selectAll + data + enter + append chain to create a set of groups, that each hold a rectangle;
  • the transform attribute in line 36. This applies to a (group of) element(s): the content of the transform string sets the actual transformation: In this case a translate (other possibilities are rotate and scale). The transform is used to draw each bar at a different position, by translating along the y-axis based on the data index.

Create a new webpage called BarChart.html using listing 5. Experiment with changing key numbers (such as the xScale constant) and other parts of the code to see how it influences the visualisation.

Using D3's data-dependent scaling

A weakness of the code above is the use of the arbitrary number 10 to set the xScale. We use it to scale the width of the bars, depending on the data value. The value of this number should depend on the domain of the data (the minimum and maximum value, in this case 0 and 50 respectively), in relation with the desired width of the chart (500px = the svg width). But of course these dependencies are only implicitly defined in the value 10, and if the data changes, this number should also be changed. That's not what we want...

We can make these dependencies explicit and eliminate the "fixed" number by using a linear scale, dependent on the actual data. D3's scaleLinear() function specifies a linear mapping from data space (domain) to display space (range):

Although xScale as before looks like a constant, it is now actually a function: For any given data value in the domain (which in line 30 is set as an array from 0 to the maximum value found in the data), the function returns a scaled display value in the range (which in line 31 is set between 0 and the width of the svg. For example, an input value of 4 returns 40, and an input value of 16 returns 160. To use the new scale, simply replace the hard-coded multiplication (xScale * d) by a call to the xScale() function in the appropriate location (line 42).

To understand how this makes scaling flexible, implement the changes mentioned above and experiment with changing the width of the SVG by changing the number in line 26 var svgwidth = 500 and/or the data values in line 25. Notice how the chart adapts to the width available...

D3 scales can also be used to interpolate many other types of display-space values, such as paths, color spaces and geographic transforms, as we will see later.

Adding an Axis

The next task is to enhance the chart's usability by adding a value axis. Below we mention the building blocks needed, you should figure out yourself where these should be placed, what values to use, and to test the results in your browser. The final chart should look like the figure below. The solution will appear in due time in the Solution Listing at the end of this page...

D3 has a powerful mechanism to add axes to graphs, charts and maps. You define an axis by telling d3 to create an axis function: const theAxis = d3.axisBottom(xScale);
The parameter you provide to this function is the d3.scale() it should use to determine the values. If your axis should appear below the chart, you use the axisBottom(scale) function (the other possibilities are, not surprisingly, axisTop, axisLeft and axisRight).

The resulting object (here named theAxis) can be used to render multiple axes by repeated application using selection.call(). Think of it as a rubber stamp which can print out axes wherever they are needed. The axis elements are positioned relative to a local origin, so to transform into the desired position we need set the "transform" attribute on a containing element. Often we use the general SVG grouping element "g" for this:

<someElement>.append("g")
  .attr("class", "axis")
  .attr("transform", "translate(x, y)"
  .call(theAxis);

The axis container should also have a class name so that we can apply styles. The class name "axis" is arbitrary; call it whatever you like. The axis component that d3 will create consists of a path element which displays the domain, and multiple .line elements for each tick mark. A tick in turn contains a text label. Most of d3's examples therefore use the following minimal style in CSS:

.axis text {
  font: 9px sans-serif;
  fill: black;
  }
.axis path,
  .axis line {
  fill: none;
  stroke: black;
  }

You will also need to make room for the axis below the graph. To do that, you'll have to make the svg height bigger then the height needed for the chart bars alone!