Be the first user to complete this post

  • 0
Add to List

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

One of the first things that you encounter when working with d3js is the notion of selections, namely - update, enter and exit selection. At times, it might seem a bit confusing for starters when and why you need to use selections to manipulate your visualizations. In this article, we will visualize the concept of d3js selections so that the next time you will be able to use them with absolute confidence. D3 stands for Data Driven Documents, and as its name suggests, d3 gives data the highest priority in its methods. What this implies for us in the context of selections is that when you perform a selection and combine it with data, the object that is returned tells you something about the dom with respect to the data that you supplied. Lets go through an example 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 purpose of our example, let say that we want to create a list item for each data unit in our 'multiples' 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 elements to display our data points, we want to create 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 necessary to be aware of three important terms Update Selection: Represents mappings to DOM nodes that already exist on the DOM for which there exists a corresponding data point. Enter Selection: Represents mappings to DOM nodes that will need to be created in order to map the excess data points. Exit Selection: Represents mappings to DOM that dont have corresponding data points. The DOM nodes of these mappings will probably 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 = container.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 selection, the value that is immediately returned is the update selection itself. The enter and exit selections are properties on the update selection 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 wondering how does the data actually get mapped to the DOM nodes?
Aha! By default D3 maps your array to the DOM nodes using index positions. i.e. it matches elements that have the same index in the result of the DOM selection to the data points that have the corresponding index.
enter image description here <image></image> The next AHA moment for me was when I realized that I can actually specify my own criteria when mapping elements by passing a second criteria to the data() function.
AHA! : You can specify your own function - a key function - in the second argument to the data() function. This function 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 number, we will need to specify our own mapping function.
// Create a one-on-one mapping of the node with the data array.
var updateSelection = children.data(multiples, function (d) {
    return d.num;
});
However 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 specify a key function, it gets executed 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 function is executed using its data. If not, you get a null mapping which essentially becomes a part of your enter selection just like before. And if a DOM node does not match with any data point after executing its key function, it becomes part of your exit selection. Armed with this knowlege, you can now act in confidence and create/remove elements 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 function sequence like the above dont panic and just remember the visualization that we saw earlier. Cheers!



Also Read:

  1. d3 Fundamentals: Creating a simple bar graph
  2. Using d3js to draw a bar chart with an axis and some basic transitions
  3. Render a d3js Tree as a React Component
  4. Selecting a node in d3js based upon the value of its data
  5. Render a d3 tree with a minimum distance between the tree nodes