Introduction to Data Visualization with d3.js v4 Scales and Axes
This course has been updated! We now recommend you take the Introduction to D3.js course.
Transcript from the "Scales and Axes" Lesson
>> Shirley Wu: So how was this code sample? Did it help in terms of the enter append, the data binding? Okay, cool, because this is the first part. I like to think of it as like data binding is one of the core parts of D3 and then also enter-update-exit is one of the core parts of D3.
[00:00:21] And I personally maybe in a biased view think that if you just grasp those two the rest of the D3 library makes so much sense.
>> Shirley Wu: Okay, so this is where we kinda go a little bit outside that core part and then just have a little bit of fun or what I think is fun, which it's not.
[00:00:42] So let's go into scales and axes because now that we have like a bar chart, maybe we want people to be able to see what your axes are. Or actually the other things is like we give, for this one, for my examples thus far we give really nice values, right?
[00:01:02] Between zero to 200 renders nicely on the screen. But what if you had data whose values were between zero and one. If you just rendered that as height, it won't really show up for you. Or will like, if your height was you know a thousand something. Like 2,000, or 10,000 or something like that.
[00:01:23] So, let me, you know to drive that home, like. I'm changing the wrong one. Like that's not gonna be cool in your visualization. So that's were D3 scales come in really, really helpful. And I find it like, it's one of those like a born utility that's amazingly helpful.
[00:01:53] Because trying to code this scales by yourself, as my co-instructor admitted try to do is really painful, and there's a lot of edge cases. So the way that I like to think about scales is so this is scale linear, which is one of the, actually let me show you the documentation for it.
[00:02:14] So anytime that you want to use scale, it's under d3/d3-scale. And these are all the different kinds of scales that D3 provides. So under continuous, that should be a continuous input and a continuous output. And there is a linear and then, all these different ones. And so for this example, I'm just going to show you scale linear, which is, I guess that's pretty self explanatory.
[00:02:48] If I say it's a linear scale, that's pretty self explanatory. As opposed to like a log scale, okay. [LAUGH]
>> Shirley Wu: So with a scale, the two things at minimum that you need that's required is to set the domain and to set the range. And the domain, you can think of it as the input, and the range as the output.
[00:03:17] And so I think the way that we use scales a lot in D3 is to think of it as mapping your data attributes, your data values to the display. And the data attributes are the domain and the display is the range. And what I mean by that is maybe you have in your data like dates, so time or like in our previous one it was like just values, right?
[00:03:47] Maybe you have like temperature or maybe you have currency values, or whatever is in your data, you want to be able to convert that to something that's displayable in the screen. So maybe that's an x value, like maybe you map the date to your x value. And maybe you map your temperature to your y value, or maybe you mapped that to your, like within height or if you have a circle then maybe it's your radius, or maybe it's your opacity.
[00:04:16] Whatever the translation between those two are, that's what scales are amazing for. So I have just a really simply example of something of how you could use a scale. So the first one is maybe your domain is 0 to 100. But actually maybe you want to turn that into opacity so you need that mapping to be 0 to 1.
[00:04:43] So you give it 0 to 100, so you set- And the domain and ranges that you pass in have to be an array, if the min and the max. So for both of them, you pass in your min and max, and then it gets mapped for min to min and max to max, this, yeah.
[00:05:08] Okay, so for this one you know 0 to 0 and 100 to 1, all the in between. You can also flip it, this is why I just realized min and max are probably the wrong examples. But it's basically the first value of maps to the first value and the second value of maps to the second value.
[00:05:24] So you can if, that whole height that we were talking about before where with SVG your y value goes from zero to increasing. And then so you have to do that weird like, for the y value you have to be height minus your data. With scales, all you got to do is be like, okay, so I have this data that goes from 0 to 100.
[00:05:49] And actually, I want to map that 0 to 500 because that's my height. So the data is 0, but then because you want the height of your bar graph to be 500, that places it at the bottom of your chart. And then my biggest, my 100, my max becomes the 0 y value.
[00:06:17] And that way when you use the scale, you don't have to do anything complicated like crazy, it just maps nicely to the screen, not upside down. So that's another way you can use the scale, there's plenty of ways that you can use it. So what I said earlier about needing to pass in an array with, usually it's an array with your min and max.
[00:06:45] If you thought like, okay how do I go through and get min and max of an array, right? Of values of my data. D3 has that taken care of for you too. So you can just be like d3.min. So d3 has these like array, I think the module is d3 array.
[00:07:05] So array utility functions where you just say d3.min, you pass in your data, and you're just like, this is the attribute that I want to get the min and max on. Does that make sense? This is my accessor. So if I pass in the data, and then my accessor.
[00:07:27] And I can do that same thing for max. You want to be getting the min and max individually. Or if you're lazy like me, you can use extent which basically gives you back the min and max which I, when I found that out I was like, mind blown.
[00:07:48] I get mind blown a little bit really easily. And the way that you can use that is, for example, this is how I defined my yScale. So scale linear and then I get the domain Which is the extent that I calculated earlier, and then I mapped that, because the extent is min and max.
[00:08:13] I mapped that to my height, and zero for my y value, kind of like what I was talking about a slide before.
>> Speaker 2: Yes, we have a question from Alex. Is this primarily a transform of the x and y-axis? Let's say that we had some data and we want to place it in a chart.
[00:08:35] Is this primarily going to wind up determining how high up or how far down something is, or how left or right it is on that canvas?
>> Shirley Wu: You could use it that way. So you could definitely use it as where do I place things on the screen or how far do I want to transform, but you're not limited to that.
[00:09:07] I feel like anything that's mappable, like anything, I feel like you could do, you can use skills for almost anything. You can do opacity, radius. If you have, for example, there's also ordinal scales. So if you have a, I think this is a discrete ranged mapping, sorry, mapping a discrete domain to a discrete range, I think, should be orbital, yes.
[00:09:49] [LAUGH] So if you have like a set of categories, maybe you have a bar chart of animals or something like that, you have cat, dog, and your value is how much people love them for your [LAUGH] x-axis, you can use this thing called scale band, where you say my input is an array of values of cat, dog,
>> Shirley Wu: Parrot, goldfish, and it can be any length, whereas when we were doing scale linear, and it was continuous. I was telling you that it has to be the min and max, right? With the ordinal scales it could be any length of values as long as that's kind of your input.
[00:10:50] And then make sure to read the documentation, because it has so many different kind of scales. But for scale band, so for some of them, you have to make sure to like, if you have you know eight, eight values in your domain. You have to have eight values that it maps directly to for your, range, and then there are some of them that you could be like.
[00:11:19] Here are my like eight inputs, and then I just want you to give me, and then I just tell it like, I want you to map it between 0 and 1,000. And then it will go and figure out like, so there's eight things, I should have 0 and 800, make my math easier.
[00:11:38] [LAUGH] and then go ahead and be like, each of these pets will be 100 pixels wide and they will figure out all of the x values for you. So scales are amazingly helpful and also definitely one of the things that you should pick, and choose, and read about.
[00:11:59] So I use scale linear a lot. I use scale log a lot. I use scale log when there's a few data points that are really, really large, and then the rest of them are really small. So if you use that scale linear then it's basically a bunch of really large things, and then really tiny things and you can't see it.
[00:12:29] So then if you use scale log, it kind of smooths that out a little bit. So I use that a lot, and I use scale band a lot for ordinal domains, but there's more excitingly esoteric things. I think quantize is if you have a discreet, if you have, I think, a continuous domain, yeah, continuous domain and discreet range, and so you can do crazy fun things with these scales.
[00:13:06] But, and I forgot scaleTime, scaleTime is amazing also. If you just have a bunch of dates, and scaleTime is also continuous, so continuous domain to continuous range. So if you just say I want you to map from January of 2017 to December of 2017, and then, I want you to map it between 0 and 1000.
[00:13:30] And it will just calculate that for you, and I think it's a lifesaver, because how do you, I don't even know how you would go about coding that continuous scale, [LAUGH] yeah.
>> Speaker 3: For first scaleTime, is there a way to define custom time stamps then? So you can say like it's in this month, year, hour formatted?
>> Shirley Wu: Do you mean like when you display it?
>> Speaker 3: Well, like if your data's in a like non-standard timestamp.
[00:14:28] And then you can just pass that into scale time, but if it's truly weirdly non-standard, you first need to convert that to a valid date object to pass it into scaleTime. I think scaleTime will only accept, let me verify that. ScaleTime, I believe, only, so I'm guessing either a string or a date object.
[00:15:00] So you need to get it into a valid form, but D3 has you covered there also, because D3 has this thing called D3 time that helps you parse, it basically, I think, so D3 timer, maybe it's D3 time format, sorry. We have D3 time and time format.
>> Shirley Wu: D3 time format that helps you be like, it,
>> Shirley Wu: Yeah, you tell it, this is what my date, my non-standard date looks like, translate that into a validate format for me. Yeah, so it won't be solved by scale, but can be solved by another module in D3. I think this is why like people are like, D3, so amazing.
[00:15:55] Yeah, [LAUGH] so scaleLinear, scaleLog, and scaleTime for continuous things, and then usually I use scaleBand for ordinal. So these are all of the Scales. And then now we can- so Scales are only just like that mapping that translation. And then when you want to like display that Axes, then there is retreat Axes that takes your Scale.
[00:16:25] And basically renders that, translates that to a set of axes. It renders the axis into your DOM for you. So let me really quickly kinda go through this code, and what's happening. So this one's just saying, I want my axis to be on the left. Wait, sorry, let's step back.
[00:16:48] On the left, and the scale that I want to use is the y scale I defined earlier, and then what I'm doing here is I'm saying okay, I want to render that axis into a Into the DOM. And I want to get the svg and I want to append this thing called a group element, g group element.
[00:17:20] Which is just this svg element that's kind of like this container that helps you have loads of other svg elements inside it. So I wasn't gonna get too deep into SVG, but with SVG you can't nest elements. You can't nest a circle element within a rect element. Or the only thing that you could nest is this thing called group elements, and that group is kinda like Yeah, the container that will hold your rect and circle and whatever, text elements, etc.
[00:17:53] And you can apply transformations to that whole group element. So you can just be like, this whole group element I want you to move to 200x and 100y, or something like that and it transforms all the rectangles or circles or whatever you have inside it, and the reason why you might want this is because what D3 axes does for you underneath the hood is basically create a bunch of path and.
[00:18:25] Text elements to render that axis for you. So you need the group element to kind of contain that. And most of the time, you might want the axis to be not 0, 0 on the screen. So you use transform translate, so this is saying translate 40 pixels Across and 20 pixels down, and then call the axis to render.
[00:18:57] And what that looks like in this tiny little thing, is that's what ends up getting rendered.
>> Speaker 3: In standard HTML CSS equivalent is that almost like creating a Div to hold and putting that DIv 20 pixels Down and to the right.
>> Shirley Wu: Yeah, yeah.
>> Speaker 3: So the g is like a div and then it's like putting in your CSS?
>> Shirley Wu: Yeah, yeah.
>> Speaker 3: Move this 40 pixels over and down.
>> Shirley Wu: Yeah, you can think of it that way, definitely. But you can only call axes D3 axis, and SVG, and maybe Canvas now, in V4. I haven't checked with Canvas. But you can only do it with SVG or Canvas because, wait let me strike out the Canvas, cuz I'm not 100% sure, but I think in V4 does Canvas now.
[00:19:55] But you can only do it with SVG because it creates like Specifically text and line and path elements that each time it wouldn't support, so that would be the only thing. But yeah, if you want to think of it as that translate is basically like applying-.
>> Speaker 3: Like conceptually it's like making a div and moving a div with CSS almost but it's the SBG equivalent.
>> Shirley Wu: Yeah. Okay. And you might want to do that if you have the x axis. You don't want the x axis to render at 0,0, right? You want to have that at 500 pixels down, or something at the bottom of your bar chart, or something like that. So, that's why that one is really helpful.
[00:20:42] And then again, a really tiny screenshot to kinda show you. I think it's important to show you here that I wanted to get across is that don't be afraid of what d3 access is because underneath the hood, like this is all it's doing, you have that g, the g element that gets created.
[00:21:04] And all d3 is doing is making like a bunch of groups with ticks and pads and to render this thing. And so you could actually if you want to do something non-standard with it, that's not Imported by the API. All you have to do is be like, select all the text elements in here and apply a style, or you can work with it like you would work with any set of SVG selections otherwise.
[00:21:33] But I think most people don't really edit what's in here. But if you desperately need to for some reason, that's all it is under the hood. Questions?
>> Speaker 2: Good, so that segues perfectly into Leo's question.
>> Shirley Wu: Okay.
>> Speaker 2: Similar to how do we make this particular bar red, how would you make a particular label a particular color?
[00:21:57] How would you override just that one?
>> Shirley Wu: So the question itself is how do you make a particular, say like take, like the 64, how do you make that red? And nothing else red. But let me also answer a second part that's kind of on the ask, which is like, how do I format Like how do I format these texts.
[00:22:24] So if I want this one to be 68 but I want this to be like 6060K. Well, I want these two attributes like 68.0 somewhere like that, somewhere known headed to where. D3 is giving you, how do I do that? And that was actually going to be kind of like the play with the code part.
[00:22:48] And so that for that you could, I want to show you, if you go to in d3 access and a lot of the functionality it gives you is actually how to format your text. So either you want to specify the tics that you have. So maybe you want to say d 3 is giving me fifteen tics but I only want ten.
[00:23:18] Or I could be like, I think the one I use a lot is this thing called tickFormat where you can pass it in being like I want each of the text to be comma separated. If it's like 100,000, I want you to have a comma at the correct mark and then like I want you to have one decimal point.
[00:23:48] I want you to show one decimal point or something like that, and you can actually also pass in a function kind of like what we've been, you can pass enough function being for the odd numbers. Format it this way and for the even numbers format it this way.
[00:24:12] So that's the unasked question of how can you format the text of the text. And then let me answer the actual question of let's say, if I do Access. So if I just give that variable then the .call(yAxis) I want to say should be returning me to selection of the axis.
[00:24:43] So let's console.log that to double check.
>> Shirley Wu: This is not the right.
>> Shirley Wu: Let me do it this way. So the thing I mentioned earlier .node, axis.node, yeah. So when you do .call in axis, what that actually returns you is your axis selection So I just console.logged acess.node.
[00:25:31] And then so down here, you can see this is actually that whole access and then you can open it up and be like, these are all of the takes and stuff inside it. So if, for example, what I want to do is.
>> Shirley Wu: Turn one of the ticks red, I just say, and one of the.
>> Shirley Wu: One of the.
>> Shirley Wu: Text takes red. So now if do axis.selectAll, it will give me all the text elements within that axis.
>> Shirley Wu: So that should be.
>> Shirley Wu: So, yeah, so this is all of the text elements within it. And you can just treat that like a normal selection and say I want the fill to be if that data, actually.
>> Shirley Wu: Now I think about it, hold on, let me figure out what data that's bound to it is. .data. [LAUGH] Okay, this is the data that's been bound to each of those. So let me just say, okay, if the data is 66 then I want it red, and otherwise I want it blue.
>> Shirley Wu: Ta-da, thank you, thank you. [LAUGH] Wow, okay, you guys make me feel good. Yeah, so it just works like any other selection that we've been talking about before. This is why I get very excited about D3. I think it just like very fun. And questions?
>> Speaker 2: Yes, there was a question previously about a little bit of review for select all.
[00:27:45] Specifically, does it select only the children or does it it actually go through multiple, like children's children, or the farthest child that matches that pattern?
>> Shirley Wu: Second option I believe, I don't think about this anymore. So we need to verify it. Second option, because if you, for example, take a look at this axis.
[00:28:12] You can see that the axis is a selection, and then when we do .select all text. Its first order children are actually a bunch of group elements, and one path. So there's no text in there. So D3 actually goes in and actually looks at, looks all the way down, and finds all the text elements.
[00:28:38] And I think I forgot to mention this earlier, which is you can definitely change selections. So you can be like, select all the group elements and select all the text elements inside. Or you can be like, this access is a selection so then select everything that matches my selector inside.
[00:28:56] You can chain that and that's just helpful in terms of if you have two axes because you have the x and y but you only want to change the colors of the text in your y-axis. Then you can be like, y-axis .select all, and that wouldn't touch anything in the x-axis.
[00:29:15] So, yeah.