Back to Contents Page

Selection

Objective: In this lesson, students will learn the basics of selections in D3, giving them new tools to develop their project further.


Section 1 : Arrays

Before we introduce selection, there's something new about data that you need to know. At this point, you should know how to represent single values such as strings,numbers and booleans in JavaScript. However, you always need to deal with a large amount of values or groups of values when using D3 to visualise data, so you need a way to represent multiple values. Luckily, JavaScript provides a way to do that, using a structure called an array.

If you want to store a group of numbers:

var numbers = [1,2,3,4,5,6,7,8,9,10];

If you want to access a single value in the array numbers, you use the following syntax:

var a_number = numbers[2];

The number in the square brackets is called an index. It tells us where in the array the value is. You should always try to think of arrays as a series of things, starting at the index and increasing in a linear way from there. Therefore, the value stored in a_number will be 3. Note, the largest index of an array is the length of the array - 1 and you can’t (and shouldn't try to!) access an element using an index beyond that value.

You can also have an array of strings:

var colours = ["red", "yellow", "blue", "white"];

or an array of arrays:

var coordinates = [ [2,3], [6,9], [12,45] ];

If we have embedded arrays, then we have several indexes. We express this using the bracket notation side by side for the number of layers. You can think of this as representing the DOM structure, where the highest level is on the left, and the lowest on the right.

So to access a value:

var x_coordinate = coordinates[0][0];

The value stored in x_coordinate Will be the array at [0], which is [2, 3], and the first element of that array, which is 2.

Now, you have this crucial tool, let's proceed to the next section.


Section 2 Basic Operations on Selection

A selection is an array of elements pulled out from the the current document on which you can perform different operations such as changing styles and attributes and appending new elements. Most importantly,you can add or remove elements in response to the changes in data(I will explain this in later sections)

There are two methods for selecting elements in D3: select and selectAll. They both accept selector strings( It’s similar to the way you select elements to style with CSS).The former selects only the first matching element whereas selectAll selects all matching elements. Let’s see some examples so that you can understand:

Suppose you have <p id='text' class='paragraph'>text</p> in your HTML file, you can use d3.select("#text") or d3.select(".paragraph") or d3.select("p") (if this element is the first element in the HTML file) to select this element. If you have many elements with id='text' or class='paragraph' , you can use d3.selectAll("#text") and d3.selectAll(".paragraph") to select all of them.

In general, you select an element or elements in three ways:

Now, you know how to select a single element or a group of elements, let's see how you can change the elements you select.(I suggest you to create a new HTML file and try things out as you go through the rest of the tutorial as it would help you understand better and make the project at the end easier for you.)

Let's look at some simple text examples and later I will use svg shapes as examples since D3 is all about visualisations.

Type the following into an empty HTML file.

Open it with a browser, and you will see "D3 is fun!" on the top left corner just as expected, let's change the colour of the text:

Put the following code between the <script></script> (You should know how to do this).

var text = d3.select("p");
text.style("color", "red");

Alternatively you could write d3.select("p").style("color", "red");(Which is method chaining!)

You will see that the text has turned red. This is how you use selection.style(css_property_name,value),. Both css_property_name and value are strings.If you want to change the font size of the text, you would use text.style("font-size", "30px"); .

<p>D3 is fun!<p>:

text.attr("class", "sentence");

To see whether we actually added a class, add the following code:

d3.select(".sentence").style("font-size","30px");

Now open a new file type the following:

You will see an unordered list on the top left corner, let's change the colour of each list item and append a description to each list item:

d3.selectAll("li").style("color", "red").append("p").html("description");

You should see something like this:

You might wonder why all the "description" elements are red since we only changed the colour of the list item. This is because selection.append(name) appends an element as the last child of each element in the current selection. Because we set each list item's colour to red, each "description" we append would inherit the colour. The name inside the brackets should be DOM element name in a string form, for example, "p", "li", "svg".selection.html(value) sets the inner HTML content to the value you specify.

Now, let's review what we have learnt so far with some SVG(Scalable Vector Graphics)elements.

Open a new file and type the following:

You should see four black circles on the same line:

Exercise1

Using selection: 1.Change the colour of the four circles to blue(note: You should use "fill" instead of "color" as the property name) 2.Change the radius of each circle to 20.

The result should look like this:


Section 3 Binding Data

Normally, we use data to change the appearance of the circles. We use selection.data to bind data to the circles. Say if we want to represent the four numbers 25, 36,49 and 64 using circles. First of all,we need to represent the values as an array.

var data = [25,36,49,64];

Then we select all the circles and bind the above data to them:

var circles = d3.selectAll("circle");
circles.data(data);

At this point, this values in the array have been bound to each of the circles. To be more specific, 25 is bound to the first circle, 36 is bound to the second circle and so on.

Now let's see how we can use the data bound to the circles:

circles.attr("r", function(d) { return Math.sqrt(d);});

You will see 4 circles with increasing radius:

< You can see from the above statement, instead of using a number as the second argument to the attribute function, we use a function that returns the square root of each value in the array. Let's take a closer look at the function. The d inside the parentheses is called an argument of the function which you can use to compute some values inside the function. After we bind the data to the circles, each value inside the array can be accessed as the first argument to the function, namely, function(d) { return Math.sqrt(d);}. In this case, the letter d is used to refer to the data. You can use any other valid variable name instead. Math.sqrt() is a JavaScript library function that takes a number as its parameter and returns the square root of that number.

For example:

var sqr = Math.sqrt(4);

The value stored in sqr would be 2. There are many other useful math functions in JavaScript such as Math.random() which returns a number between 0(inclusive) and 1(exclusive). You will need to use some JavaScript math functions for the final project so you’d better do some research online to see what functions are available to you. The function function(d) { return Math.sqrt(d);} returns 5 for the first circle and 6 for the second circle and so on.

Maybe you have noticed that I said that each value inside the the array can be accessed as the first argument to the function we passed to selection.attr. This means that we can pass other arguments as well. Indeed, we can pass a second optional argument to the function we passed to selection.attr. Let's see an example:

Delete circles.attr("r", function(d) { return Math.sqrt(d);}); and add the following

circles.attr("cy",function(d,i){ return 40*i+40; });

You should see:

The second argument is the index of elements you’ve selected. The first circle element has an index of 0 and therefore its y coordinate is changed to 40. The second circle element has an index of 1 and its y coordinate is 80(note: The origin of SVG is the top left corner) and so on.


Section 4 Entering Elements

In the previous section, we have 4 values corresponding to 4 circles. What if we have 5 values now?

var data = [25,36,49,64,81];

We don't have enough circles to represent all the values. Of course, we can add another circle manually and then we would have enough circles. But D3 provides a powerful alternative which is enter selection.

D3 puts any extra data into the enter selection when binding data to elements. In our case, the fifth value would be put into the enter selection and the other 4 values would be returned normally by selection.data.

After binding the five values, we can then append circle to the enter selection so that the fifth value will have a corresponding circle. Let's look at an example:

var svg = d3.select("svg");
var circles = svg.selectAll("circle").data(data);
circle.enter().append("circle");
circle.attr("cy",60);
circle.attr("cx",function(d,i){return i*30+30;});
circle.attr("r",function(d) {return Math.sqrt(d);});

The result looks like this:

We select the svg element first this time. Why? Because the selection.append appends an element as a child to the selection and all the circle elements are the children of the svg element. In the extreme case in which there's no circle elements in the svg element, you can still use selection.enter and selection.append to create new elements for any leftover data. You usually follow this method sequence selectAll + data + enter + append.


Section 5 Exiting Elements

You use exit selection when you have too many existing elements and you want to delete some of them. Exit selection contains elements that have no corresponding data. Say we now have two numbers 25 and 36 and we want to remove the two extra circles:

var svg = d3.select("svg");
var circles = svg.selectAll("circle").data([25,36]);
circles.exit().remove();
circles.attr("r",function(d) {return Math.sqrt(d);});

The result:

Author : Mingqian Wang