- What Are Data-Joins?
- A Conceptual Overview of Data-Joins: Enter
- Enter and Binding Data
- Using a Data-Join to Make a Bar Chart
- Using Anonymous Functions to Access Bound Data
- Finishing the Rest of the Chart
- Storing Data in Objects
- Summary
Using Anonymous Functions to Access Bound Data
As the name suggests, an anonymous function is a function that doesn’t have a name, or technically speaking, it hasn’t been bound to an identifier. (What were its parents thinking?!) While a named function might look like this:
Figure 5.7 After the data-join
var myFunction = function(){ return 5; }
a similar anonymous function would look like this:
function(){ return 5; }
or, since it’s a small function, we could be concise and write on one line, like this:
function(){ return 5; }
Anonymous functions, like regular functions, can take arguments. So, you could have an anonymous function that looks like this:
function(x){ return x + 5; }
Anonymous functions are used in a lot of different programming languages, and there are a lot of different reasons for using them. When it comes to D3, you use them primarily to gain access to bound data. So, as far as our code goes, we are going to replace “What goes here?” on this line:
.attr("width", // What goes here?)
with an anonymous function, such that it will look something like this:
.attr("width", function(){})
D3 has a couple of conventions when it comes to using anonymous functions to access bound data. The reasons for these conventions are a little complex, but the good news is, you don’t need to know them to use D3. You just need to memorize the conventions themselves.
The first is that the function always takes an argument called d:
.attr("width", function(d){})
and d has a very specific meaning. For each of the elements in our selection, it represents the bound data point. So, for our first rectangle, the value of d is 1.6. For the second, d is 1.5, and so on.
This is great, because we want to set the widths of our rectangles to be equal to the values in popData. For each rectangle we want the width to be d. How do we do that? Just like with any other function—we tell our anonymous function to return a value of d:
.attr("width", function(d){ return d; })
Perfect. Now on to the attribute y. We also want to use an anonymous function, something like this:
.attr("y", function(d){})
Hmm...the problem is that the vertical position, y, doesn’t have anything to do with the value of the bound data. Remember that when we used a loop to make the rectangles, we set y equal to our iteration variable, i, times a constant, barSpacing. We never once used any of the data contained in popData. So, we don’t need to use d.
Fortunately, D3 gives you access not only to the value of each bound data point, but also to the index of each data point within your data array. How do you access those indices? By introducing another argument to your anonymous function—i.
.attr("y", function(d,i){})
So, for our first rectangle, i is equal to 0, for the second rectangle, it’s equal to 1, and so on.
Just as before, we want y to be equal to the index times our constant, barSpacing. Easy:
.attr("y", function(d,i){ return i * barSpacing })
And here’s the chain in its entirety:
barGroup.selectAll("rect") .data(popData) .enter().append("rect") .attr("x", 0) .attr("height", barHeight) .attr("width", function(d) {return d}) .attr("y", function(d,i) {return i * barSpacing});
which we can rearrange so its ordered in a more sensible way:
barGroup.selectAll("rect") .data(popData) .enter().append("rect") .attr("x", 0) .attr("y", function(d,i) {return i * barSpacing}) .attr("width", function(d) {return d}) .attr("height", barHeight);
Figure 5.8 Data-driven rectangles
Put that in your code and run it! You should get what you see in Figure 5.8.
A word of congratulations is in order. You have now used all three Ds. You have driven a document with data. Huzzah!
One final note on using anonymous functions in D3 to access bound data. As mentioned, you always need to include d as an argument, no matter what. That’s the first convention of using anonymous functions. When we set the value of y above to i * barSpacing, we didn’t use d at all. That doesn’t matter—we still have to include it as an argument.
The second convention is that you don’t need to include i unless you plan on using it. When we set the width attribute above, we didn’t need i, and so it appears nowhere in the anonymous function. But if you are going to use i, you have to make sure it is added to your anonymous function as an argument as well as being in the body of your function.