Introduction to Data Visualization with d3.js v4 Challenge 1: Solution
This course has been updated! We now recommend you take the Introduction to D3.js course.
Transcript from the "Challenge 1: Solution" Lesson
>> Shirley Wu: I just wanted to say right after I gave you guys this exercise and we broke for lunch. I realized I shoved you guys into the deep end and was like swim. So we had some really great questions. The first of them being, it probably be helpful if we kind of just broke down how SVG works for just this exercise.
[00:00:25] So, I think one of the confusions that came up was because we talked about each of the axis being within in SVG, and appending a group, and then calling the axis. Like do we need an SVG for each of the axis and then like all of and does all of the like you know rectangles need to be in SVG like it does it need to be 3 SVG's.
[00:00:49] And the way to think about as SVG is it's kind of like, you can think of SVG kind of like the HTML documents, so you can just have one and then you append everything to it inside. And then you can have the SVG and then you can have group elements that you put all of your elements inside if you need to like batch apply transforms to it, or anything like that.
[00:01:15] But within the SVG, it's kind of, yeah, you put your rectangles and your circles. I think one of the comparisons we were talking about is if the SVG is an HTML document, then the group is one of your divs. And then there's things inside it that are your subdivs, and that's kind of the comparison.
[00:01:40] So that was one of the first things, and the second thing is let's kind of talk about the things that are happening here. So there are these rectangles that are make up the bar charts, and then that's the first part. And then there is the y-axis and there is the x-axis.
[00:02:05] So how was the exercise, actually? And then I can take questions really quickly here, too. Yeah.
>> Shirley Wu: [LAUGH] How was the deep end?
>> Male off screen: It's okay.
>> Female off screen: Sort of it?
>> Shirley Wu: Okay, and then questions from online also?
>> Male off screen: Yes, we did have one question online, Jonathan asked why in the code example do we increment each temperature by one?
[00:02:38] Eg++ d, bracket city end bracket?
>> Shirley Wu: Okay, so we can dive right into this code, and then essentially this is all it means is when the data gets loaded in as loaded in. Sometimes the data is all in string and then, so if you console log the data right now,
>> Shirley Wu: You see this is an array of data, and then you can see it's actually, well, ignore the San Francisco cuz well okay, so all of the values are in string and then all that the plus plus does is converts it to integer or a flow, yes flowed.
[00:03:32] And that's all it is, its just like a super neat like shorthand that's converting it to an integer.
>> Female off screen: So the top part I think, we were a little confused took, cuz normally that means increment within a function. But that top part, from D3 TSV, the data for each, that's basically just, it's actually not a function in the same way with increment.
[00:03:56] It's like defining the data types.
[00:04:27] But I see now that I caused confusion. Okay, but let's get going and the first thing we want to do is create the rectangles.
>> Shirley Wu: So let's, and then this is our data, so we want to make a rectangle, so let's get right into it. So let's actually first select the svg, d3.select svg and feel free to stop me at any time with questions, and if I'm looking down and I can't see, please wave your hands.
[00:05:14] So let's select the svg, and then let's just create the rectangles so, I take the svg and I select all the rectangles that don't yet exist and I bind my data to it.
>> Male off screen: Where did that data come from? That data data, where does that variable come from?
>> Shirley Wu: Just right here?
>> Male off screen: So how does it get from the d3 tsve, into a variable that you can edit here without going outside the scope of the tsv. I guess, I can see in the d3.tsv.data is a variable you're passing into that function.
>> Shirley Wu: [CROSSTALK]
>> Male off screen: How does that variable become available to your data down here?
>> Male off screen: It's still within that scope. [CROSSTALK]
>> Shirley Wu: Yeah, yeah, yeah.
>> Male off screen: And so this is all in the tsv?
>> Shirley Wu: Yes, if you want to use it outside, you would have to set like a, yeah, but yeah it's still in the function, the same function, yeah, thank you.
[00:06:24] And then, so that's how I'm using the data. Okay, so enter append and now if we inspect the svg, we should see roughly 300 rectangles created. Is that exciting? [LAUGH] Okay, okay now,
>> Shirley Wu: I lied a little bit because I realized we probably need to use, we need to actually define our skills first so that we can set the x and y attributes.
[00:07:00] I mean, if we want to right now just say like width let's set the width to 5, and actually, that's all we got right now. So for everything else, for our x and y, and our height, we actually need our scales. So first, let's do the the x scale.
[00:07:28] So we said that x is going to be the time, the date, so we do scaleTime, and then we need a domain, and then our range, did we say? Okay, so our range, we want it to be 0 to width, or?
>> Shirley Wu: 0 to width, or?
>> Male off screen: It's gonna have to start over the amount that we translate the y axis, right?
>> Shirley Wu: So, let's just say there is a convention with d3 where we define the margin. And we say top is 20, bottom is 20, something along those lines, left is 20, and right. And we're just like super verbose about it just in case we want to push down, only the left or, and so then what we can do.
[00:08:23] As we say okay, so we actually want to start with margin left.
>> Shirley Wu: And then, we only actually, because we want to be within the bounds of the SVG element. We want to actually do only draw until with minus the margin right. So this will very nicely give us the right place to draw the x attribute.
[00:08:53] And then now let's figure out our extent, our min and max.
>> Shirley Wu: And the data that we want to be getting for the extent is the date.
>> Shirley Wu: And let's console.log that to see what it looks like.
>> Shirley Wu: And this is our extent, our min and max for the x axis, so it starts in October 2011 and then it goes until September 2012.
>> Shirley Wu: Gonna stop console logging the data also. Then,
>> Shirley Wu: Then let's do the y. So for the y, I think I set my city as San Francisco. So let's get the temperatures for San Francisco.
>> Shirley Wu: And so that's apparently our min and max for San Francisco, wow.
>> Shirley Wu: Is it just me or does that look not right to you. Yeah. [LAUGH] Really? Our temperatures. Okay, well, I trust d3 extent.
>> Female off screen: That's my stereotype of San Francisco.
>> Shirley Wu: Okay, we have like, we have like a little bit more range than that I feel like. [LAUGH]
>> Male off screen: Well the question is whether you have that difference in the timeframe that you're looking in [CROSSTALK]
>> Shirley Wu: Fair enough, to 2011 to 2012 because apparently for New York, okay so New York has a range. Yeah I guess 2011 to 2012 we just-
>> Male off screen: We're okay.
>> Shirley Wu: We were just, yeah.
[00:11:19] I did not notice that. Okay var yScale, this one should be a what scale?
>> Female off screen: Linear.
>> Male off screen: Linear?
>> Shirley Wu: Yes, thank you. It should be scaleLinear, .domain, so pass in the yExtent, and then pass in, and in this case, we want our 0 to actually be at height minus margin, right?
[00:12:00] Height- margin.bottom, so that's where we want our 0 or like our min to be mapped to. And then we want the tallest of our temperatures to be mapped to margin.top. Did that make sense?
>> Shirley Wu: Okay, I'll take that as a yes.
>> Female off screen: And we're inverting it again for the same reason so that it starts with like more canvas style coordinates and not the cartesian?
>> Shirley Wu: Yeah, we're inverting it just so we don't have an upside down.
>> Male off screen: Okay, yeah.
>> Shirley Wu: Yeah, the upside down, yeah, bars.
>> Female off screen: Cuz the browser's coordinates work differently from regular graph coordinates.
>> Shirley Wu: Yeah, okay, so just for fun let's put in like- so this is the other thing that came up which is [LAUGH], I completely forgot to mention this before we broke which is, how do you use a scale?
[00:13:15] And a scale is actually, once you've, like passing your domain and range and all of that, it's just a function that you can then pass your, pass anything into. So for example, if I just say, okay, what, like yScale and then what is 50 degrees? And then, you can see, it is apparently 167.87 blah blah blah pixels.
[00:13:44] And that's where my y is for 50 degrees. If I do like you know, a 100, it will be actually negative 20 pixels because a hundred is actually passed our like our max. Cuz our max for New York was like 80 degree. So then a hundred is pass that, so then you see that it's actually like taking that into a count and being like it's negative 20 pixels if we go with the scale.
[00:14:09] There are some really nice functionality with d3 scales where you can say, I think the function is called .clamp. And .clamp is like if you use .clamp is true, then you pass in like a hundred, it will actually only return you zero, it will only return you, I mean your margin.top.
[00:14:32] Like it won't go pass the min and max that you set for your range. So that's very helpful but yeah this is.
>> Male off screen: Can you talk one more time about why are we inverting, why if you don't do this margin top, height minus margin top and margin bottom and then margin top.
[00:14:51] It appears underneath the x-axis and we have to do this for it to appear in the regular above the x-axis. You know what I'm saying?
>> Shirley Wu: The x-axis do you mean just like the right here the 0?
>> Male off screen: No, no, I meant, I mean the y axis, the values in the y axis.
[00:15:13] You know how you're doing height minus margin.button there and then margin.top and you have to do that so things appear above the axis. They are still on the y axis but they appear but if you instead did-
>> Shirley Wu: The other way around, the margin.top-
>> Male off screen: [CROSSTALK] It will all appear at the back, why is that?
>> Shirley Wu: Because the coordinate system for SVG is, this top left corner is 0,0.
>> Male off screen: Okay.
>> Shirley Wu: Yeah, so the coordinate system goes, yeah, x-axis is 0, and then it goes 0 down.
>> Male off screen: Okay, okay, got it.
>> Shirley Wu: Yeah, so which is counter-intuitive to how we think about Like cuz we expected to be from the bottom is zero and then you go up.
[00:16:08] For like yeah.
>> Male off screen: Regular math, yeah.
>> Shirley Wu: Yeah [LAUGH] And yay programming screens [LAUGH] Yay. Yeah so let me also drive home VM, how do you use those scale, you use it like you would use any other function and you pass in a values. If you pass in an invalid value like
>> Shirley Wu: It will simply give you a NaN or if you don't pass anything in, it will give you a NaN. So that is how you use a scale,
>> Shirley Wu: And that is one of the things I failed to tell you before I pushed you into the deep end because I like to keep your lives interesting.
[00:16:56] Okay, so now that we got that, let use the scales that we just defined. And the way that we use it is essentially, for example, that X scale is for sending the X attribute, so we want to just use that as sorry d.d
>> Shirley Wu: And then now if we inspect the element, we should see that each of the rectangle elements now has a correct x, attribute value because we return x scale and then passed in d.d and that got translated to right pixel value.
>> Shirley Wu: So far are we good? Cool, okay, so lets do the y attributes.
>> Shirley Wu: And I am just using function verbosely. So now it is the y scale and then the data we decided to use was the temperature for our city.
>> Shirley Wu: Now if we take a look,
>> Shirley Wu: At each of our rectangles, now we have the right y positions also. And you can see, I think I might have set my height to only 300, so like all of the y functions are like between 0 and 300.
>> Shirley Wu: Cool, but notice that nothing is showing up still because we're still missing our height.
>> Shirley Wu: And we could have either made another scale for our height but our height is actually just,
>> Shirley Wu: Basically, oops,
>> Shirley Wu: Our height is actually our height minus,
>> Shirley Wu: It's actually just this.
>> Shirley Wu: And I think I have a question.
>> Male off screen: Yes, well the first question that's relevant to this immediate part, there's some question about what's in the margin object?
[00:19:55] Could you just scroll up and show the margin object, and maybe zoom in a little bit so that people can see it.
>> Shirley Wu: No, we forgot to zoom in.
>> Male off screen: It's pretty simple, yeah.
>> Shirley Wu: We forgot to do the zoom in on my-
>> Male off screen: So does everybody see that there's a margin object and it just has a top, a bottom, a left, and a right?
[00:20:15] Yeah, okay, that's sufficient.
>> Shirley Wu: Okay.
>> Male off screen: Perfect.
>> Shirley Wu: And this is back to the width height x, y, attribute.
>> Shirley Wu: And so, does it make sense what I had to do with the height? Instead of making another height scale, I was just let me just subtract my y scale from the height.
[00:20:40] Actually, for the sake of,
>> Shirley Wu: Being,
>> Shirley Wu: Thorough. Let's just make a height scale. So the domain is still the yExtent right? Because essentially my domain should just be the min and max of my city temperature. And then but my range could just be from 0, too height- 2 times margin.top- margin.bottom.
>> Shirley Wu: Then I could just use my heightScale and pass in my city temperature and that does exactly the same thing. And I had to do
>> Shirley Wu: Height. So my height goes from zero and I am subtracting- margin.top and- margin.bottom to count for the fact that in my y I'm like, I only do I subtract out them like in my Y, I say I only want you to render to the part of the screen, -margin.bottom and -margin.top.
[00:21:57] So, I have to reflect that in my height.
>> Female off screen: Yeah, Is there a difference, I just noticed you're using two different selectors for D.Date and then D bracket city?
>> Shirley Wu: The bracket city is just because I have city defined up top as New York and so I'm essentially just Accessing d.NewYork.
>> Male off screen: But it's a string. So it has to be in the bracket or something like that.
>> Shirley Wu: Yeah, yeah that's just, it's a variable.
>> Male off screen: [INAUDIBLE] The space in there, yeah.
>> Shirley Wu: Well, no, this one is because city is a variable It's a variable, so I can't just access it with the dot because the dot assumes that that's the string.
[00:22:49] So, I'm using a bracket here because I'm using city as a variable. Yeah.
>> Shirley Wu: And then the only other thing I really did was give a fill of blue.
>> Shirley Wu: And then stroke it white. And now I see that the width is like kind of humongous I just
>> Shirley Wu: Made it back to two.
>> Shirley Wu: Yeah, so this is. I shouldn't have saved that cuz this is my starter. I'm.
>> Shirley Wu: Yeah, any questions so far?
>> Male off screen: We have a question about changing data. So far, we've made an awesome graph, it looks great. We've got a piece of data that comes in, we show the temperatured data.
[00:23:42] One of the questions that we receive was saying forget the tangent but what happens when our data like our temperature data is constantly changing like it's a real time source? Will that be covered?
>> Shirley Wu: Yes, so that, when the data changes, and that's basically the enter update exit pattern?
[00:24:03] And we'll be covering that right after the shape section. Yeah, I just wanted to get you guys drawing a bar chart before all of the rest of the confusing, interrupting exit thing.
>> Shirley Wu: So we will get there and we will get there in detail. Okay, so now that we have the rectangles, all that's left is actually for us to define our axis, and to just append them to our svg.
[00:24:36] So, let's do,
>> Shirley Wu: Axis and we want our x axis to be at the bottom.
>> Shirley Wu: And the scale that we want to use is xScale, and for our yAxis, we just want it to be at axisLeft, .scale(yScale).
>> Shirley Wu: Then, I'm, and then all we gotta do is that same svg we defined up top or selected up top, we just append that group.
[00:25:19] And then, actually let's call it, let's call the X axis and see what happens. So notice how it actually is, it scooted over on the x axis properly for us because the x scale starts with the margin that left of 20 pixels. So that's actually correct but we need to push that down so that it's right below our bars, right?
[00:25:47] So let's set our transform and we just want to translate by,
>> Shirley Wu: I just like using an array to do this, but let's translate the x by 0 because it's already got the 20 pixel margin thanks to the xScale. And then let's translate it down, and it should be height- margin.bottom is how much we translate that down by.
>> Shirley Wu: Oops, yeah and then, for our svg.append, call y axis.
>> Shirley Wu: You can see there is that little bit of a line here because it's correct because we just need to push it over,
>> Shirley Wu: By the margin left.
>> Shirley Wu: So,
>> Shirley Wu: So push it over by margin left, and we don't need to do any pushing on the y axis.
[00:27:19] Because the y scale has already taken care of that for us. And this is why it's super nice to have that margin object. Because you see that 20 pixels over isn't actually enough room. So I can adjust the margin left to be like 40 pixels, let's say. So that all of the axes will show up.
>> Shirley Wu: And that's it, this bar chart, super straightforward, right?
>> Male off screen: It was.
>> Shirley Wu: Yes, and awesome. Yeah?
>> Male off screen: So [COUGH] for putting the rectangles in you have to go through each of these attributes, is there a shorthand where you could define an object that would be all of those attributes that you could pass in there?
>> Shirley Wu: I think d3 used to let us do that, where you say, you just used one.adder and you will do an object with. And keyed by like xy with high and then values are the functions that returns that. I think d3 used to let us do that and it seems like d4 doesn't.
[00:28:27] I haven't, I'm just now used to this pane of writing it out and I haven't tried that. But you could give it a try or read the documentation, but I think you have to write it all out. And then you had-
>> Female off screen: Yeah, I was just curious .call, what is that actually doing?
>> Shirley Wu: Okay, so .call underneath the hood, and then this .call is in the selection module. So you can read the documentation there, but .call is essentially just a nice chaining shorthand for underneath the hood that's what it's doing is,
>> Shirley Wu: And that is it. So in this case the selection is svg.append, this whole part, right of the svg and we appended the g.
[00:29:21] And we did the transform so that's our selection that is getting passed into the y axis. So all that is happening underneath the hood. There is however some things about what this is. You can read the documentation for more details about yeah. But yeah so y axis, just taking that selection and creating a bunch of like groups and text and stuff to draw that axis.
>> Male off screen: And then we got a couple more questions, one question is about the x axis for dates. Why is it displaying the month names instead of the specific dates? And how were the number of ticks figured out? How did it figure out how many of those to do?
>> Shirley Wu: D3 Mike Bostock black magic.
>> Male off screen: Yes.
>> Shirley Wu: I don't actually have the exact answer for the second question because I've never looked at the axis code underneath the hood. I think he guesstimates in his code. But if you want, for example, very specifically only 10 ticks. You can actually specify that.
[00:30:29] You can say, it takes, is that 10, 1, 2 let me do something that's like,
>> Shirley Wu: Yeah, so if you only specifically want a certain number of ticks, you can pass that in. Although this one for some reason isn't giving you like the actual text, but you can see there are specifically five ticks.
[00:30:54] And then there is also, I think the other question was, so for the x axis, d3 is smart enough to know that hey, you pass me in a scale. That's a scale time, so that's why I should be putting out dates. But if you want it to,
>> Shirley Wu: For example, if you want it to, I don't know what's interesting.
>> Male off screen: For example, October 2011, November 2011, right, as the tick, right.
>> Shirley Wu: Yeah let's,
>> Shirley Wu: I don't know these off the top of my head. Let me say like d.getMonth, is that, wait,
>> Shirley Wu: Hold on. getFullyear,
>> Shirley Wu: You can. How do I get the month? Hold on, let me do it this way.
[00:32:10] d3.timeFormat and then I think it's percent.
>> Male off screen: One of the comments here is %B.
>> Shirley Wu: Thank you. That's, and then you can pass in your date, yeah, there we go, yes, thank you. %Y, %Y, yes.
>> Male off screen: Hey, look at that.
>> Shirley Wu: And then I think if you do %B, it's the short hand, the three-letter months and so this is how we can.
[00:32:39] And, again, notice that this basically gives you back a function. And then you use that function and pass in your data and that's how it's doing the tick formats. Another way, a similar thing is I'm actually. If you just say d3.timeFormat and then %B %Y, the same thing as previous.
[00:33:07] These two lines are doing exactly the same thing because time format returns you a function that takes in your data. And so this line and this line are exactly the same. Yeah, so I want to mention this and I want to highlight this fact because if you look at d3 code, if you go through blogs and you find people's blogs.
[00:33:35] I think one of the big sources of confusion is you see people just doing this and you're like, wait, why is that giving me the right set of return values? And that's just because this is actually just a function that takes in your data and spits out the formatted date, yeah.
[00:33:55] [BLANK AUDIO] Cool, is there another question?
>> Male off screen: The last question is it seems that one of your axes starts at 20, how would you start it from 0? So if you could just show where the off-set of the drawn axis is in your code.
>> Shirley Wu: In my x-axis?
>> Male off screen: I think it's the y-axis actually, so how far left or right it is.
>> Shirley Wu: Okay, let me repeat that to see if I understood. So my y-axis, it's currently moved over 20 pixels to the, over 20 pixels and what would it look like if it's just 0?
>> Male off screen: Yeah, just like not moved over at all.
>> Shirley Wu: Okay, so I will just comment out this transform and this is what it looks like. So it looks like you can't see anything because it's starting at zero and then it's getting clipped off because all of the ticks and stuff are to the left of it.
[00:34:59] And you just can't see anything. And that's why it's pretty important to include the transform translate.
>> Male off screen: I think the other part of that question might be that the numbers on your scale. The first tick is at 25 and then it goes to 30 so it looks like they're incrementing by 5.
[00:35:17] And if you start that at 0, you'd change the extent.
>> Shirley Wu: Yes, perfect, thank you very much, I see, I see. Okay, yeah, so that's why I also showed the whole minimax thing, so. Yeah, so that could be like super confusing if actually I think in some cases all I want is the max.
>> Shirley Wu: So that I can just say I want it to always start at 0, my y should always start at 0. Despite if values, even if the min is 20 degrees, I want it to start at 0 degrees, and then the top is. There we go. So now, it starts at 0 and then goes all the way until 80 where as before it went from 20 to 80 because that was my minimax.