I've been learning more about the d3 visualization library, and I've seen a few examples of bar charts that have a snippet that looks like
chart.selectAll("rect")
.data(data)
.enter().append("rect")
.attr("y", y)
.attr("width", x)
.attr("height", y.rangeBand());
My confusion is with the first selectAll
line. What is the purpose of selecting all rects before they exist since we'll be appending new rects on data enter? Does what goes in the selectAll matter if none of those elements exist?
It is part of the declarative nature of the D3 language. The Thinking with Joins article explains it in detail. An excerpt:
But what’s with the selectAll("circle")? Why do you have to select elements that don’t exist in order to create new ones? WAT.
Here’s the deal: instead of telling D3 how to do something, tell D3 what you want. In this case, you want the circle elements to correspond to data: you want one circle per datum. Instead of instructing D3 to create circles, then, tell D3 that the selection "circle" should correspond to data—and describe how to get there. This concept is called the data-join:
This Venn diagram illustrates the data-join. Data bound to existing elements produce the update (inner) selection. Unbound data produce the enter selection (left), and unbound elements produce the exit selection (right). Data Enter Update Elements Exit Thinking with joins reveals the mystery behind the sequence:
The selectAll("circle") returns the empty selection, since the SVG container element (svg) is empty. No magic here.
The empty selection is joined to data: data(data). The data method binds data to elements, producing three virtual selections: enter, update and exit. The enter selection contains placeholders for any missing elements. The update selection contains existing elements, bound to data. Any remaining elements end up in the exit selection for removal.
Since the selection was empty, all data ends up as placeholder nodes in enter().
This is the same append as in the first example, but applied to multiple placeholders; selection methods implicitly iterate over selected elements. The missing elements are added to the SVG container by append("circle").
So that’s it. You wanted the selection "circle" to correspond to data, and you described how to create the missing elements.
In your example selectAll("rect")
is called first. But it returns an empty selection.
data(data)
will bind the empty selection with the data. It creates new empty selections.
.enter()
identifies any DOM elements that needs to be added when the joined array is longer than the selection.
append("rect")
appends a rectangle to each empty selection, which is no longer empty
It is well explained and detailed on this section: D3.js data binding, How it works?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With