Enter and Binding Data
Ok, let’s check out Frank’s data. Say you’ve already done some number crunching, and you’ve added up all the covers for each celebrity for every month and sorted them into rankings. Figure 5.2 shows what you found for the first three months, January through March, 2009 (these values are, of course, completely fabricated).
Figure 5.2 The first three months of Frank’s data
Here are a couple of notes concerning the data:
- The number of covers doesn’t always add up to 50. This is because sometimes cover shots feature two celebrities together, and in those cases, it counts as a cover for both of them.
- There were only four celebrities total in cover shots in January. A lot of attention was paid to the Brad Pitt/Angelina Jolie saga. (What would Frank say that means about the country?)
- February was similar to January, except that Weekly World News provided an update on its famous “bat-child.”
- “Octomom” was the nickname given to Nadya Suleman after she successfully gave birth to octuplets in early 2009.
A nice way to structure this data in JavaScript is to create a couple of arrays of objects. For example, for January, we would have:
var janData = [ {name:"Angelina Jolie", covers:20, rank:1}, {name:"Brad Pitt", covers:18, rank:2}, {name:"Jennifer Aniston", covers:10, rank:3}, {name:"Britney Spears", covers:8, rank:4} ];
Can you see what makes that structure so nice? The array janData contains four objects, and each object contains all of the information for one (and only one) data point. We’ll go over data structures more in Chapter 7.
Alright, so first things first: We need to get some graphics on the page. Let’s forget about the bars for now and start with just the celebrity names. We could take the approach we used in Chapter 4, in the section “Shaping Web Pages with D3 Selections,” using a for loop to append one text element for each name. But we aren’t going to do that. Forget for loops. We’re thinking in data-joins now. We want to make text enter the page.
Here’s how: We’re going to create a selection of all the text elements currently on the page, and then we’re going to join our data to it. But wait...our page is blank. There are no text elements! So what does it even mean to “select allof them?”
Herein lies the magic of how D3 handles the enter phase. You create a selection of elements that don’t exist using d3.selectAll(). In this case, since we want to make text enter the page, we can select all of the not-yet-existing paragraph elements—d3.selectAll("p"). This is shown conceptually in Figure 5.3.
Figure 5.3 An empty selection
Then you use two methods on that selection: data() and enter(). This one-two punch does something truly awesome: It creates a new object for every point in your dataset. Yep, that’s right—you don’t have to tell D3 how large your dataset is. You just join it up with an empty selection, and it will create the right number of objects for you (see Figure 5.4).
Figure 5.4 The magic of data() and enter()
Those objects are just placeholders to start—no text elements have actually been added to the page yet. To make that happen, we just have to use our trusty old friend, append(). We’ll append a paragraph element to each of those placeholders (see Figure 5.5).
Figure 5.5 Replacing the placeholders with text elements
Now, we’ve put four text elements on the page, but they don’t have any text in them, so our page is still blank. How do we get those celebrity names up there and in the right place? The secret lies in the data() method. That method actually performs a data-join, and when D3 performs a data-join, it binds data to elements. So, each of those text elements actually has a data point connected, or bound, to it, as shown by the lines in Figure 5.5.
D3 gives us easy access to bound data, so we can use that data to tell the text elements what to say and where to go: “Alright, element, let’s look at your data point. Which celebrity do you have? Angelina Jolie? Okay, that’s what I want your text to read. And what’s the rank? 1? Okay, you’re going to the top!”