This course has been updated! We now recommend you take the Introduction to D3.js course.
Transcript from the "Challenge 3: Solution" Lesson
>> Shirley Wu: Before we get into this exercise and how it works and all of that, I want to make sure to cover three things that arose in the break. The first being, there were some questions while we were talking about the enter, update, exit about how to use that within React.
[00:00:21] Or any of the other MVC frameworks that with a V part might also want control of the dom. So if there is enough people that are interested in it I have after this exercise, one more section about the force layout. And then after that I was just planning on open Q and A, so if enough people are interested we can cover React and D3 in that section.
[00:00:48] And I have a talk that's about 15 minutes long that I can go through for that, so let me know. The second thing is earlier we were talking about, so there is an old introduction to D3 that I did. This is working off of version 3, there's some parts that are a little bit broken.
[00:01:15] So when you put in the data, you have to make sure to do comma space comma space. But if you play around with this it gives a nice intuitive feel of how enter, update, exit works. And for example, if you just do this and then you run code and that's not what you were expecting.
[00:01:48] But if you guys want to play around with this little site in your own time so that you can get even more of an intuitive feel about how enter, update, exit works. I've covered pretty much everything that you need to know about it in our workshop and in my slides.
[00:02:04] But if you want to just get away from having to actually write the code to create the divs and stuff. And you just want to play around with, if I do this data and then do append or enter append, what happens, and get the sense from that. It's at my website sxywu.com/c3intro, yeah I've gotten good feedback on it that it helped a lot in terms of trying to learn, enter, update, exit, that's the second thing.
[00:02:38] And then the third thing that we were talking about during break is we learned something that was really cool which is I did not know this. But if you notice, the first time around, when we do the transitions, and we set duration 1,000, that one gets transitioned over one second.
[00:03:03] But after that, all of these are super fast and I never thought to think about why it was super fast. Turns out it's because after the first time, this actually solves so many questions that I had when I was working on other things. But it turns out, once you've called D3 transition, and the timer has started, etc., any subsequent times, I'm guessing this is it, I haven't dug into it or anything.
[00:03:30] It turns out, all of the subsequent times it seems to default back to the default settings for D3 transition. So that's why actually, after we applied it the first time around, all of these are now getting transitioned with a 250 millisecond duration which is the default. So if we just put this into the update bars function and redeclare it every single time, then it actually does the correct behavior.
[00:04:06] So every single time that we need to call a transition and we need to recreate it, redefine it, yeah. And now it's behaving correctly and animating over a second as opposed to 250 milliseconds that it was before. So something cool I learned today, thank you.
>> Shirley Wu: Cool, okay so now on to the exercise, how was it this time, was it manageable, was it understandable?
>> Speaker 2: I made a circle [LAUGH].
>> Shirley Wu: You made a circle?
>> Speaker 2: That's about the extent.
>> Shirley Wu: Okay, let's go through it and you guys can struggle with me because it's not like I memorized this course, so tell me what to do if I look stuck.
>> Shirley Wu: I should have saved that, well, okay, cool, let's see, I'm going to just start by console logging our response.
>> Shirley Wu: How many people were able to get it to animate, update, like through the states and animate? 30 minutes too short? Okay.
>> Shirley Wu: All right, hopefully I can do it in such a way that everything makes sense okay, so this is what each of the data looks like.
[00:05:52] So then we're using the attribute site and we're using year and we're going to use yield, I'm going to ignore the other attributes in here. So the first thing we want to do is we have our xscale and yscale, so let's set those. So as I mentioned previously, x-scale is in this case discreet, so we're using scale band, which means that we need to go and get the,
>> Shirley Wu: All of the unique sites and so let's see, let me call this xDomain, I'm very bad at naming things.
>> Shirley Wu: I think if I do d3.map, I think,
>> Shirley Wu: And then I pass in response and I say I want d.site, that should give me an array of 600 somethings with just the site.
[00:07:14] And I don't actually remember off the top of my head how to get a unique set of sites without,
>> Shirley Wu: Is that what you guys were expecting,
>> Shirley Wu: d3.map?
>> Speaker 3: How many sites are there?
>> Shirley Wu: There is apparently six, one, two, three, four, five, six, six sites.
>> Shirley Wu: Okay, I'm going to cheat a little bit,
>> Shirley Wu: [LAUGH] And look at my code. Response that map, okay.
>> Shirley Wu: I usually do this with low dash. Okay, so here, I'm just getting all of the sites. Let's console.log that.
>> Shirley Wu: And apparently I guess if I just pass this in, let's test this. So we have our xScale and then let's set this domain on it.
[00:08:30] And let's see if d3 is smart enough to take this array of 600 something sight names. And unique it and get the right side of domains.
>> Shirley Wu: And the way that you can see what's the domain that got set on the scale is you just do xScale.domain, and then call it without passing anything in, and look at that, d3 is so smart.
[00:08:57] It took our array of 600 site names and then it was like, okay, unique it all and then here's my domain which is this six site names. Perfect.
>> Shirley Wu: And now let's get our y scale. Well actually let's do this first. Let's get our, and I said it was yield.
[00:09:27] So, I wonder if these bugs any of you guys that I'm switching between arrow function and not arrow function. Does that bother you, guys? [LAUGH] Okay. Okay, so up to you guy's judgement call, would you like to use this extent where the min is 2.9? Or would you want to just do a min of 0 and just get the y max?
>> Speaker 4: 0
>> Shirley Wu: 0, 0, okay. I heard one person say 0 so I'm going with it. Okay, so let's do yMax and then we'll do max. And so yMax, then get our 75.5, yScale.domain is 0 and yMax. And we can console.log to double-check.
>> Shirley Wu: And it is correct, cool.
[00:10:35] Okay, so now that we have the scales,
>> Shirley Wu: I think we can start drawing the circles. What do you guys think? Right? Okay. So I'm going to, for now, call update with the response and the start year. And then, let's get started. Let's, for now, just draw the circles for the first year.
[00:11:05] Do I have a color scale? Okay, okay.
>> Shirley Wu: So, the first thing we might want to do is just set the data, filter the data by,
>> Shirley Wu: d.year is equal to year. So filter it just by. Only get the data points where the year matches the year that we passed in, cool.
[00:11:41] And that turns out to be 53 data points. And let's just make sure that they're all 1927. I mean, not all of them are, but let's go through. Cool, they're all 1927. And so those are the circles we want to make. Okay, so first thing we need to do,
>> Shirley Wu: Is get all of the circles that don't yet exist and bind data to it. Which our data is that. And then what should be our key function?
>> Speaker 4: [INAUDIBLE]
>> Shirley Wu: Yeah, apparently I do that. [LAUGH] d.key is a key function. [LAUGH] I was scrolling down cuz I felt like I defined this.
[00:12:39] Okay, and then just for the, I guess, sake of argument. Let's do exit last just to see that it's exactly the same thing. If not, then I need to relearn some things. Okay, so let's first do the enter.
>> Shirley Wu: .ent.circle. .enter.append.
>> Shirley Wu: Append circle, actually. Let's make sure they're all showing up.
>> Shirley Wu: There's 57 circles created, cool. And I never set this earlier but it was fine. It made sense that circle's here. The reason why, and we can call .enter on it, is because circles here is actually what .data returns, right? You can't call .enter on just any selection.
[00:13:57] It has to be what .data returns. Cuz I realize I didn't mention that earlier, but that was pretty apparent, right? Okay, cool. And then on enter, let's see. What are attributes we might need to set on center? Or do all of them depend on the data? We have our x attribute, our y attribute, our radius, and our color.
[00:14:30] Is it just color that, they all depend on the data, right? Cuz even the color I think we might have said was a site or do we-
>> Speaker 5: We set a color scale.
>> Shirley Wu: We set a color scale, but then how do we use it? How do we use it?
>> Speaker 7: I think we didn't invoke it yet after the data was loaded.
>> Shirley Wu: Okay, I think my computer may have frozen. I took a look at the other one, and it turns out that the color, the fill is actually that last. Do you remember how there's also the gen on the data?
[00:15:12] I think that's the genome of the barley, and apparently that's what we call her by.
>> Shirley Wu: So let's get that going, enter.append, var enter is equal to, and you don't actually have to do this var enter every single time. Actually, let me show you both sides. So I could either do enter and then enter.
[00:15:49] And do circles as enter.merge, circle. I mean, not merge, circle, sorry. Circles, the variable, and then I can,
>> Shirley Wu: Be like cx for the circle is supposed to be,
>> Shirley Wu: It was xScale and then we used sites, right, d.site.
>> Shirley Wu: Let's double check.
>> Shirley Wu: Yeah, I need to call update.
>> Shirley Wu: Okay, here we are.
>> Shirley Wu: Cool, okay so we call xScale with the d.site and we get these back and with the cx set correctly. Now,
>> Shirley Wu: Let's do the cy. yScale and we set d.yield.
>> Shirley Wu: And finally, the r,
>> Shirley Wu: Is r constant?
>> Shirley Wu: Is r constant?
>> Speaker 5: Yup.
>> Speaker 6: No, we're driving it, right?
>> Speaker 5: No.
>> Shirley Wu: Did we?
>> Speaker 5: You said a radius variable that time.
>> Shirley Wu: But it's a constant 10. So, actually,
>> Shirley Wu: Sorry, what I meant was, is the radius dependent on the data? And apparently the radius is not dependent on the data.
[00:17:41] It's just a constant 10.
>> Shirley Wu: Yehey, and it appears. [APPLAUSE] Okay, and then finally let's give it a fill.
>> Shirley Wu: Colors actually I think, yeah colorScale(d.gen). And then it's colored.
>> Shirley Wu: Cool.
>> Shirley Wu: And then,
>> Shirley Wu: I did lie earlier.
>> Shirley Wu: The exit selection should be above the enter and update.
[00:18:35] Only if, if and only if you've set circles to the enter and update selection. So if I don't have that, circles is still that what .data gave back so then I can say exit.remove like normal. But if I, here do circles equal, to then I overrode what .data gave back with the enter and update selections so then that .exit function will no longer work on that.
[00:19:08] So I think that's why, that's probably why we do it like that so that, cuz sometimes you will need that, so you'll need to reset that circles variable so that you can act on it, if you nest elements and stuff. So usually better to just remove first, yeah.
[00:19:29] But you could put it down there if you don't override circles with a new function. I also want to show, we don't have to set the enter variable all the time. We could also just do this.
>> Shirley Wu: So this does exactly the same thing because up until this point it's the enter selection.
[00:19:56] And then we're merging the enter selection with the update selection of circles and so it has exactly the same, the exact same effect. The only time you might want to separate out the enter selection is from the- the only time that maybe you want to do the enter first and then merge enter and update separately in two different variables is if you are needing to nest a group elements.
[00:20:33] So if you're entering a group element, and that group element actually has rectangles and text underneath it then you might need to declare the enter selection and then only create the rectangle and text on the enter selection. Because you don't want to do that again in the update selection or else you'll create extra rectangles and text every single time you update.
[00:20:59] So that's the only time you might want to separate out,
>> Shirley Wu: That you might actually want to separate out the enter like this and then merge the enter with the update separately. But if you don't need to nest anything, like if you don't need to work on just the enter selection, or append on just the enter selection, then you can just have this and that works fine too.
[00:21:27] Cool, so this do everything and,
>> Shirley Wu: And then,
>> Shirley Wu: Actually now,
>> Shirley Wu: This will actually update correctly or should update correctly every second, yeah. So this doesn't have the transition yet but, that's actually all the code you need,
>> Shirley Wu: To go between each of the, yeah. So that's all that you needed.
>> Shirley Wu: And then, let's put in our transitions. I don't think we needed to transition the x. Let me hold on and comment this out so we don't get that same problem again. Actually, is so far so good for you guys? Cool, okay, so,
>> Shirley Wu: We said we wanted to animate the x and the y.
[00:22:37] No, not the x, not the x because the sites should be the same. But the yields could change between years and also, I think I did something fancy where I just animate the radius of the circle down to zero, and then exit it. Okay, so that means all we have to do is, let's define the transition,
>> Shirley Wu: Within our update function, var t = d3.transition and let's transition for a second. And then, for our exit selection, let's transition t and then attribute r down to zero. And then we also said we wanted to transition just the line attribute.
>> Shirley Wu: So, with those three lines we should get the right animation.
[00:23:50] So I'm going to uncomment this and then see if we get the right image. Yehey, notice that all of the things that are entering are like slopping down from the top because, do you guys see that? It's like any of them, I guess, it's not entering for a while.
[00:24:09] But when it enters that, so yeah, there we go. It drops down from the top because our y attribute is defaulting to zero, which is the top, and it's dropping down like that. So if we don't want that what we can do is just after the enter selection, we just say, hey, for our y,
>> Shirley Wu: When you enter, just start with the y that,
>> Shirley Wu: That y so that you don't get that drop. If you want the drop, that's like totally up to you. But,
>> Speaker 7: So that just preserves the y from the previous selection?
>> Shirley Wu: Yeah, I think and then there's, I think I'm not gonna go into detail about all of the different things you could do with transitions.
[00:25:12] But if you look up the D3 transition documentation, there is different things that you can do with timing. So for example, you can use a function called .delay so that you can stagger the animations that come in. So with .delay maybe you return when the animation starts like every ten seconds or something given your index.
[00:25:39] You can also chain different transitions, so if you have a rectangle and you want it to like first, or say if you have a circle and you first want the radius to expand to ten. And then you want to move it to it's right y position or something, you can also chain these transitions.
[00:25:57] I don't go into detail just because it's also another huge section that we can spend hours on.