Drawing data accurately requires a consistent and precise mechanism for mapping data values to pixels on the screen. We can accomplish this mapping in D3 using scales. There are various scales available in D3, depending on your needs. In this lesson we'll using a linear scale to map a data domain of continuous values to continuous range of pixel values. We'll render a new SVG element, setting its width from our scale.
Andy Van Slaars: [0:00] The first thing we need to do in order to start drawing data on this data visualization is to create some scales that we'll convert from our data domain to pixel values on the screen. Let's start by adding an import from D3.
[0:14] From D3, we want to import scaleLinear, and we also want to import the max utility. From here, I'm going to drop down into my component. I'm going to create a new constant, and I'm going to call it X scale.
[0:27] X scale is going to equal a call to scaleLinear that we just imported from D3. Then scaleLinear has a domain method that we're going to call on it. This is going to define the range of our data values. We're going to scale that from zero out to the max of data.
[0:45] Data is an object with multiple keys, so max is going to take a second argument here that's going to be an accessor function. It's going to take our data and we're going to tell it which value or which key to grab off of data. In this case, its value.
[0:58] We're also going to call the range method. Range is going to set the values for our pixel dimensions. It's going to scale from zero to our bounded width. Now that we have our scale defined, let's use it to draw another rectangle in our SVG.
[1:13] I'm going to drop down here below this light gray rectangle and I'm going to add another rectangle. I'm going to give this a fill of black and I'm going to give it a height. I'm just going to hard code that to 50 pixels for now. Then we're going to give it a width.
[1:27] We're going to calculate the width based on our X scale. I'm going to call X scale here. Then I'm going to pass it in just a hard-coded value. I'm going to go with 125 for now. I'm going to save this and now we'll see that this rectangle has been rendered into our SVG.
[1:44] If I inspect this element, we'll see here that the width has been calculated to a very exact number and this is based on our scale. If I were to come in here and change my hard-coded value here and say we'll make it 115 and I save that.
[1:58] We'll see that our width gets recalculated again. It's very exact because it's based on that scale. We don't really have to figure out how wide to make things to make them relative to our data. Let's see what this looks like with some of our actual data.
[2:12] Instead of calling X scale with a hard-coded value here, I'm going to refer to my data, which is an array. I'm going to grab the first item from it. Then I'm going to grab the value key off of that. I'm going to go ahead and save that.
[2:25] We'll see that the size of our bar changes a little bit. If I cycle through the data here, we can see the second element, the third element, and finally, the fourth element. Each one of those values is being shown relative to our scale.
[2:40] This approach for getting the value is a little bit awkward. Luckily, we already have a function up here that will do just this. This accessor function is something that we'll use a lot with D3.
[2:50] I'm going to extract this out, do a little bit of refactoring, so that we can use that down in our width here. I'm just going to take this accessor function. I'm going to cut it, and I'm going to define a const. We'll call it X accessor and I'm just going to set it to equal that arrow function.
[3:06] Then I'm going to use that here. Then I'm going to come down here into my rectangle and I'm going to use it to extract value from my data element.
[3:19] Get rid of that dot value and just make sure our params all match up. We'll save this and everything should still be working as expected. I can update this and I can go back to say the second element. We'll see that everything is still working. Let's make one last change.
[3:34] It's just a refactor. Everything should still work the same when we're done. We're going to take this X accessor. Because it knows about the data, and our data is being provided from the parent component, we should move this definition up into that parent component.
[3:47] I'm going to cut X accessor from chart. I'm going to scroll up, and I'm just going to grab it off of props. Then I'm going to save this. That'll break everything and that's OK. I'm going to switch over to app and I'm going to define this accessor function right inside of app.
[4:04] Then I'm going to pass it through to chart as a prop. When I save that, everything should go back to working. If the shape of our data changes, say this key name changes, we can control that at the point where the data is known.
[4:23] Pass that into chart and then chart can do its thing using those external values to make all of its calculations and display the data.