Show Buttons
Share On Facebook
Share On Twitter
Share On Google Plus
Share On Linkdin
Share On Reddit
Share On Stumbleupon
Contact us
Hide Buttons

A visual explanation of the Enter, Update and Exit Selections in D3js

One of the first things that you encounter when work­ing with d3js is the notion of selec­tions, namely — update, enter and exit selec­tion. At times, it might seem a bit con­fus­ing for starters when and why you need to use selec­tions to manip­u­late your visualizations.

In this arti­cle, we will visu­al­ize the con­cept of d3js selec­tions so that the next time you will be able to use them with absolute confidence.

D3 stands for Data Dri­ven Doc­u­ments, and as its name sug­gests, d3 gives data the high­est pri­or­ity in its meth­ods. What this implies for us in the con­text of selec­tions is that when you per­form a selec­tion and com­bine it with data, the object that is returned tells you some­thing about the dom with respect to the data that you supplied.

Lets go through an exam­ple step by step.

Lets say that we have some data in an array as shown below.

var multiples = [5, 10, 15, 20, 25];

And we have an empty unordered list in the DOM.

<ul id="#example">
    <li></li>
    <li></li>
    <li></li>
</ul>

For the pur­pose of our exam­ple, let say that we want to cre­ate a list item for each data unit in our ‘mul­ti­ples’ array and place them in the unordered list shown above.


What we wish to do directly implies a few things :-

  • We only want as many list items as there are data points.
  • If there are not enough DOM ele­ments to dis­play our data points, we want to cre­ate as many as needed.
  • If there are already excess list items with respect to the data points, we want them to be removed from the DOM.
  • If there are a few list items that are already mapped to data points, we want retain them.

At this point, it is nec­es­sary to be aware of three impor­tant terms

Update Selec­tion: Rep­re­sents map­pings to DOM nodes that already exist on the DOM for which there exists a cor­re­spond­ing data point.

Enter Selec­tion: Rep­re­sents map­pings to DOM nodes that will need to be cre­ated in order to map the excess data points.

Exit Selec­tion: Rep­re­sents map­pings to DOM that dont have cor­re­spond­ing data points. The DOM nodes of these map­pings will prob­a­bly need to be deleted.

Now lets achieve this one step at a time.

// Get hold of your container
var container = d3.select('#example');

// Get hold of all the existing list items within the container
var children = d3.selectAll('li');

// Create a one-on-one mapping of the node with the data array.
var updateSelection = children.data(multiples);

This is when I had my first ‘AHA!’ moment.

AHA ! : When you bind data to a d3 selec­tion, the value that is imme­di­ately returned is the update selec­tion itself. The enter and exit selec­tions are prop­er­ties on the update selec­tion object.

// Mappings that represent pseudo DOM nodes that can potentially
// be created for each data unit
var enterSelection = updateSelection.enter();

// mapping representing real DOM nodes that could not be
// mapped to any item in the data
var exitSelection = updateSelection.exit();

Pretty cool right? But then, you might won­der­ing how does the data actu­ally get mapped to the DOM nodes?

Aha! By default D3 maps your array to the DOM nodes using index posi­tions. i.e. it matches ele­ments that have the same index in the result of the DOM selec­tion to the data points that have the cor­re­spond­ing index.

enter image description here

<image></image>

The next AHA moment for me was when I real­ized that I can actu­ally spec­ify my own cri­te­ria when map­ping ele­ments by pass­ing a sec­ond cri­te­ria to the data() function.

AHA! : You can spec­ify your own func­tion — a key func­tion — in the sec­ond argu­ment to the data() func­tion. This func­tion needs to return a value that will be used to make a comparison.

// Lets say our data is of this form
var multiples = [{'num':2},{'num': 4},{'num': 6}, {'num': 8}, {'num': 10}];

Since now each of our data unit is in the form of a num­ber, we will need to spec­ify our own map­ping function.

// Create a one-on-one mapping of the node with the data array.
var updateSelection = children.data(multiples, function (d) {
    return d.num;
});

How­ever this is only one half of the story. You also need to know why this works. This is when I had my next AHA moment.

AHA! If you spec­ify a key func­tion, it gets exe­cuted for each DOM node as well as each data point in order to match the data point to the DOM node.

If a dom node exists, the func­tion is exe­cuted using its data. If not, you get a null map­ping which essen­tially becomes a part of your enter selec­tion just like before.
And if a DOM node does not match with any data point after exe­cut­ing its key func­tion, it becomes part of your exit selection.

Armed with this knowl­ege, you can now act in con­fi­dence and create/remove ele­ments on the DOM.

d3.select('#example')
    .selectAll('li')
    .data(multiples, function (d) {return d.num;})
    .enter() // Mappings that need DOM node creation
    .append('li') // Create the DOM nodes for those mappings
    .text(function (d) {return d.num;});

So the next time that you encounter a crazy chained func­tion sequence like the above dont panic and just remem­ber the visu­al­iza­tion that we saw earlier.

Cheers!


Ryan Sukale

Ryan is a UX engineer living in San Francisco, California.