D3 in Depth covers versions 6 and 7 of D3

Home About Newsletter
NEWSLETTER

Get book discounts and receive D3.js related news and tips.

Subscribe

D3 Selections

How to select HTML and SVG elements using D3 selections. This article shows how to select, insert, remove and modify elements, how to add event handlers, how to apply a function to selections and how to filter and sort selections.

D3 selections let you choose some HTML or SVG elements and change their style and/or attributes.

For example, if your index.html file contains 5 SVG circle elements:

<svg width="760" height="140">
<g transform="translate(70, 70)">
<circle/>
<circle cx="120" />
<circle cx="240" />
<circle cx="360" />
<circle cx="480" />
</g>
</svg>

you can use d3.selectAll to select the circles then .style to change their fill and .attr to change their radius:

d3.selectAll('circle')
.style('fill', 'orange')
.attr('r', function() {
return 10 + Math.random() * 40;
});

D3 selections also let you perform data joins (see the Data Joins chapter).

Making selections

D3 has two functions to make selections d3.select and d3.selectAll.

d3.select selects the first matching element whilst d3.selectAll selects all matching elements.

Both functions take a string as its only argument. The string specifies which elements to select and is in the form of a CSS selector string (e.g. div.item, #my-chart or g:first-child).

For example to select all elements with class item use d3.selectAll('.item').

(If you’re not familiar with CSS selectors take a look at the CSS section in my free Fundamentals of HTML, SVG, CSS and JavaScript for Data Visualization course.)

Modifying elements

Once you've made a selection you can modify the elements in it using the following functions:

NameBehaviourExample
.styleUpdate the styled3.selectAll('circle').style('fill', 'red')
.attrUpdate an attributed3.selectAll('rect').attr('width', 10)
.classedAdd/remove a class attributed3.select('.item').classed('selected', true)
.propertyUpdate an element's propertyd3.selectAll('.checkbox').property('checked', false)
.textUpdate the text contentd3.select('div.title').text('My new book')
.htmlChange the html contentd3.select('.legend').html('<div class="block"></div><div>0 - 10</div>')

Whether .select or .selectAll is used, all elements in the selection will be modified.

Note that the second argument of .classed is a boolean. I often forget to include true or false and it raises an non-obvious error message!

Here's an example of all of these functions in use:

Updating selections with functions

In addition to passing constant values to .style, .attr, .classed, .property, .text and .html you can pass in a function. For example:

d3.selectAll('circle')
.attr('cx', function(d, i) {
return i * 100;
});

The function accepts two arguments which are usually named d and i. The first argument d is the joined data (or 'datum') and will be covered in the data joins chapter. i is the index of the element within the selection.

If you want to update elements in a selection according to their position within the selection, you can use the i argument. For example to position some rect elements horizontally you can use:

d3.selectAll('rect')
.attr('x', function(d, i) {
return i * 40;
});

In the majority of cases when functions are passed in, anonymous functions are used. However you can also use named functions. For example:

function positionRects(d, i) {
return i * 40;
}

d3.selectAll('rect')
.attr('x', positionRects);

Event handling

You can add event handlers to selected elements using the .on method.

This method has two arguments:

  • the first is a string specifying the event type

  • the second is a function (a 'callback function') that's called when the event is triggered. This callback function has two arguments that are usually named e and d. e is the DOM event object and d is the joined data (which will be covered in the data joins chapter).

Up to and including D3 version 5, the callback function was passed the datum d and index i. This is a breaking change.

The most common events include (see MDN event reference for more details):

Event nameDescription
clickElement has been clicked
mouseenterMouse pointer has moved onto the element
mouseoverMouse pointer has moved onto the element or its children
mouseleaveMouse pointer has moved off the element
mouseoutMouse pointer has moved off the element or its children
mousemoveMouse pointer has moved over the element

In the event callback function the this variable is bound to the DOM element that triggered the event. This allows us to do things such as:

d3.selectAll('circle')
.on('click', function(e, d) {
d3.select(this)
.style('fill', 'orange');
});

Note that this is a DOM element and not a D3 selection so if you wish to modify it using D3 you must first select it using d3.select(this).

Inserting and removing elements

Elements can be added to a selection's elements using D3's .append and .insert methods. Elements can be removed using .remove.

.append appends an element to each element in a selection. If the elements already have children, the new element will become the last child. The first argument specifies the type of element.

As an example let's start with 3 g elements, each containing a circle:

<g class="item" transform="translate(0, 0)">
<circle r="40" />
</g>
<g class="item" transform="translate(120, 0)">
<circle r="40" />
</g>
<g class="item" transform="translate(240, 0)">
<circle r="40" />
</g>

You can append a text element to each using:

d3.selectAll('g.item')
.append('text')
.text('A');

resulting in a text element being added to each g.item:

<g class="item" transform="translate(0, 0)">
<circle r="40" />
<text>A</text>
</g>
<g class="item" transform="translate(120, 0)">
<circle r="40" />
<text>A</text>
</g>
<g class="item" transform="translate(240, 0)">
<circle r="40" />
<text>A</text>
</g>

.insert is similar to .append but it allows us to specify a second argument which specifies (as a CSS selector) which element to insert the new element before.

In this example, .insert is used and the second argument is 'circle':

d3.selectAll('g.item')
.insert('text', 'circle')
.text('A');

This results in the text element being inserted before the circle:

<g class="item" transform="translate(0, 0)">
<text>A</text>
<circle r="40" />
</g>
<g class="item" transform="translate(120, 0)">
<text>A</text>
<circle r="40" />
</g>
<g class="item" transform="translate(240, 0)">
<text>A</text>
<circle r="40" />
</g>

.remove removes all the elements in a selection from the page. For example, given some circles, you can remove them using:

d3.selectAll('circle')
.remove();

Chaining

The return value of most selection methods is the selection itself. This means that selection methods such as .style, .attr and .on can be chained. For example:

d3.selectAll('circle')
.style('fill', '#333')
.attr('r', 20)
.on('click', function(d, i) {
d3.select(this)
.style('fill', 'orange');
});

.each()

The .each method lets you call a function for each element of a selection.

The callback function has two arguments usually named d and i. The first argument d is the joined data (or 'datum') and will be covered in the data joins chapter. i is the index of the element within the selection. The this keyword refers to the current HTML or SVG element in the selection.

Here's an example where .each is used to call a function for each of the selection's elements. The function computes whether the index is odd or even and modifies the circle accordingly:

d3.selectAll('circle')
.each(function(d, i) {
var odd = i % 2 === 1;

d3.select(this)
.style('fill', odd ? 'orange' : '#ddd')
.attr('r', odd ? 40 : 20);
});

Note that this refers to the current HTML or SVG element (or the ith element in the selection). If you wish to modify it using D3 you can select it using d3.select(this).

.call()

The .call method allows a function to be called into which the selection itself is passed as the first argument.

.call is useful where you want a reusable function that operates on a selection.

For example, colorAll takes a selection and sets the fill of the selection's elements to orange:

function colorAll(selection) {
selection
.style('fill', 'orange');
}

d3.selectAll('circle')
.call(colorAll);

Filtering and sorting selections

You can filter a selection using D3's .filter method. The first argument is a function which returns true if the element should be included. The filtered selection is returned by the filter method so you can continue chaining selection methods.

In this example you filter through even-numbered elements and colour them orange:

d3.selectAll('circle')
.filter(function(d, i) {
return i % 2 === 0;
})
.style('fill', 'orange');

Sorting only really makes sense if data has been joined to the selection, so please read up on data joins first.

You can sort elements in a selection by calling .sort and passing in a comparator function. The comparator function has two arguments, usually a and b, which represent the datums on the two elements being compared. If the comparator function returns a negative number, a will be placed before b and if positive, a will be placed after b.

Thus if you have the following data joined to a selection:

[
{
"name": "Andy",
"score": 37
},
{
"name": "Beth",
"score": 39
},
{
"name": "Craig",
"score": 31
},
{
"name": "Diane",
"score": 35
},
{
"name": "Evelyn",
"score": 38
}
]

you can sort by score using:

  d3.selectAll('.person')
.sort(function(a, b) {
return b.score - a.score;
});
BOOKS & COURSES
D3 Start to Finish book cover

Visualising Data with JavaScript teaches you how to build charts, dashboards and data stories using Chart.js, Leaflet, D3 and React.

Find out more

"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."

Javier García Fernández

Learn how to make a custom data visualisation using D3.js.

Find out more

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

Find out more