D3 Selection Mysteries… Solved?

Edit: It was brought to my attention that I should acknowledge the excellent resource for learning D3 provided by Scott Murray in his book Interactive Data Visualization for the Web and in his AlignedLeft blog tutorials. I can’t say enough about how well-written and beginner-friendly the book and tutorials are. This post is simply meant to extend the understanding I got from reading Murray’s blog post on Binding Data, which I highly recommend reading first.

The selectAll-data-enter sequence used to create multiple selections in D3 has always been a bit mysterious to me. I even went so far as to call .enter() “one of the great mysteries of the universe” while teaching it. But it’s really not all that mysterious. I don’t know why I didn’t think to do this until now, but a simple series of console.log statements can reveal the stages of multiple selection creation and data binding.

1. Empty selection:

var provinces = map.selectAll(".provinces");
console.log(provinces);

screenshot1

Here we have an empty selection. Note that it is simply an empty set of nested arrays. I’m still not sure why this is a nested array instead of a single-layer array, but I’m sure there’s a good reason. In any case, the inner array appears to be what’s important.

2. Adding the Data:

var provinces = map.selectAll(".provinces")
    .data(topojson.feature(europe, europe.objects.FranceProvinces).features);
console.log(provinces);

screenshot2

When an array of data is added to the selection, a number of blank slots are created in the array that matches the number of elements in the data array.

3. Binding the Data:

var provinces = map.selectAll(".provinces")
    .data(topojson.feature(europe, europe.objects.FranceProvinces).features)
    .enter();
console.log(provinces);

screenshot3

What do each of those data objects look like?

screenshot4

Enter binds the data to the selection, so that each element in the selection array is now an object holding its datum within the __data__ property.

4. Appending an Element:

var provinces = map.selectAll(".provinces")
    .data(topojson.feature(europe, europe.objects.FranceProvinces).features)
    .enter()
    .append("g")
    .attr("class", "provinces");
console.log(provinces);

screenshot5

So what’s in each <g> element?

screenshot6

Notice how the datum (__data__) has been attached as a property of the element. This is what gets passed every time a method further down in the block calls an anonymous function with a d parameter.

Smell that? That smells like… understanding.

Bonus! Here’s the video of Mike Bostock’s awesome keynote at FOSS4G2014 back in September:

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s