The goal of this tutorial is to give an introduction to d3.js by using the example of a simple animated bar chart. Before anything else, let’s take a look at it. Click on any bar of this chart -you can do it multiple times- to see what happens!
So why use a low-level framework to draw graphs when so many integrative chart libraries exist out there (Highcharts , Google Chart Tools …)? Precisely because it is low-level. That means you have to put in more effort upfront, but in return you gain total control of your data visualization, you are more flexible, and you can freely use the full power of existing technologies (CSS3, HTML5, SVG …) to visualize data however you want (as a graph or otherwise).
This example uses SVG. It’s not a problem if you are not used to it, as it is very straightforward, but you may still want to check the MDN tutorial on SVG. Now let’s take a look at the code for the chart:
The first thing you should notice is that d3 uses method chaining. Every d3 function returns a d3 object on which you can apply another d3 function. This makes for code that reads almost like a sentence, for example the first line would be “select the div with id d3TutoGraphContainer and create a SVG element with width 600 and height 300”.
This is the core of D3: selecting elements of the DOM, and doing stuff with them.
D3 uses CSS3 selectors, also used by jQuery. You can select nodes by tag name, css class or id.
d3.select(selector) selects the first node matching selector and returns a d3 object
containing this node on which you can apply any d3 function.
d3.selectAll(selector) selects all nodes matching selector and returns a d3
object containing these nodes on which you can apply any d3 function. So in our example:
1 2 3
You can also apply
select to an existing selection, to select among the children
of the existing selection. This is usually useful to ensure that all d3 manipulations
will take place in a container div (‘d3TutoGraphContainer’ in our example):
1 2 3 4 5
Inserting in and removing from the DOM
d3 provides functions for inserting in and removing from the DOM.
As usual, these functions apply to d3 selections.
Note : you may ask why use these functions when we can use jQuery for example. The answer is simple : even though you could do it, d3’s DOM manipulation functions are designed to work with other d3 function, so you can use method chaining. It is thus easier to use d3 and only d3 to build a data-driven document.
Inserting in the DOM
selection.append(tag) appends an element of the specified tag as the last child
of each element of selection. In our example:
1 2 3 4 5 6 7 8 9 10 11
There is another way to insert elements in the DOM:
which inserts, as a child of every element in selection, an element of type name
before the first element selectable by the CSS selector before. This is useful to
control which SVG elements appear on top of the others (the last one in the page is on top).
Removing from the DOM
Removing all the elements from a selection is done with the
like this :
selection.remove(). This is often used with the
exit() function, also covered in
the “Binding data” section below.
Binding data is the core of d3. The
d3.data function binds data to the selection
to which it was applied, and returns three selections:
- The update selection: all the DOM elements from the selection to which we could bind data
- The enter selection: the ‘surplus’ (if any) data for which there was no DOM element
- The exit selection: all the ‘surplus’ (if any) DOM elements for which there was no data
Of course, at least one of the enter and the exit has to be empty, both are if the data
has the same size as the selection. In our example we use
1 2 3 4 5 6 7 8 9 10 11 12 13 14
d3.data() directly returns the update so you can immediately do something on it (that’s our #2).
If you want to work on the enter or the exit you need to call
the update (that’s our #1).
Modifying the DOM according to the data
Now it’s time to use d3 for what it was designed: manipulating the DOM using the data. We can modify any attribute of an element, CSS classes, properties, text and even inner HTML.
Modifying attributes: d3.attr
selection.attr(attribute, value) modifies (and creates if it doesn’t exist)
the attribute attribute to give it the value value for every element of selection.
value can be a function of data and element index, as in our example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
As this is not a reference, I won’t show all functions that modify elements.
You can look into the d3 reference
to learn how to modify classes with
d3.classed, properties with
d3.property and style with
The last, and maybe the most impressive piece of d3 is the transitions engine.
As we saw in the previous section, d3 enables us to modify any attribute instantly.
It can also transition number attributes (e.g. position in pixels, width etc)
from their old to their new value smoothly, using the
delay() functions. You apply this function to any selection and then apply
the new attributes, which will be transitioned. In our example, we transition the width
of the bars to animate the graph:
1 2 3 4 5 6 7 8 9 10 11
Cool, isn’t it ? The use of
delay() is optional, as you can imagine. The
transition() function can
transition number attributes, but can also understand when a
string contains numbers, and smoothly transition the number parts of the string -that’s how I
built the rainbow transition in the example at the top of this article. It also understands some specific
types of strings, for example colors (i.e. it can transition from ‘steelblue’ to ‘red’). Visit the d3.js website for more on this!
What I explained are just the default, basic transition engine, which works very well. You may need to customize your transition interpolation function, tween or easing function. For example, I did that to animate a line chart (which is a SVG path).
With this tutorial, you should know more than enough to create awesome custom graphs or data visualizations. Since you have total control, you can even create this kind of crazy animations!
Also, it is the only way I found to build smooth animated graphs on the iPad, other libraries such as Highcharts were too slow.