Fundamentals of Rendering Data as an SVG Bar Graph with D3, scaleBand, and scaleLinear

Jason Brown
InstructorJason Brown
Share this video with your friends

Social Share Links

Send Tweet
Published 6 years ago
Updated 5 years ago

In this lesson we'll start by using d3-scale to build up a scaleBand for our x data and a scaleLinear for our y data points to allow them to map and extrapolate our data correctly to renderable bars. We'll add in padding between each bar, and then using the svg rect will render a collection of bars.

Instructor: [00:00] We have some data that we're importing. It steps from 0through 10 on the X-axis, and 1 through 500 on the Y-axis. The reason we have a one here is so that we can see the data show up, but the you'll likely have a zero if you have zero data there.

[00:18] We'll start by setting up our data selectors. We'll say const x selector, which will be an arrow function that's given the data point and returns d.x, because that's how our data's set up. Then the same for the y selector.

[00:33] We'll need to import two scales from d3 scale. I'll import scaleband and scalelinear from d3 scale. We'll first set up our scale y, our y scale. I say const y scale, which will be a scalelinear.

[00:59] We'll need to set up our range. Our range will be the height first to zero, and then we will map our domain of data to zero and 500. This 500 is our y max value. That means that our zero will map to the height, which will be the lower end of the svg, and our 500 will map to zero, which will be the top of our svg.

[01:28] Then we need to set up our x scale. We'll stay const xScale = scaleband. We'll need to set our range. Our range will be zero to the width of our svg.

[01:41] Then we'll need to set up our domain. Our domain needs to be passed all of the data coordinates, all the data points that we have, which is 10 of them. The reason is that scaleband will take all of those data points, and then create bands that we can render into.

[01:58] Those bands will be of an even width. If we tell it that we have 10 data points, then it will create 10 areas that we can render our bar graph into. I'll say data.map, which will be d, which will be our data point, and then pass our x selector our data point. That way, we have our range with our maximum width, and then all of our data points.

[02:26] To make sure that there is space in between each of our bars, we'll supply a padding. We can do a padding inner or a padding outer. This is a ratio between zero and one.

[02:38] We're saying 03, which will say 03 of the bar widths will be the padding on inner, which is in between each of the bars, and then on the outer, which is on the left and the right side. If you specify 05, then spaces in between the bars and the bar widths themselves would be identical.

[03:00] Now we need to create our bars. We're going to say data.map, and map over all of our data. We'll receive a d and our index. Now we need to calculate the height of each of the bars. We'll going to say first our const * y value, which will be a yScale, which will scale our data point to the y-axis. I say y selector and pass in our data point.

[03:31] Now, with our y value, we need to create our bar height. We say const bar height, which will be the height of our svg minus the y value. Now we'll render our bar. We'll reuse the rect svg element. We'll give our key our I, so we don't get warnings.

[04:01] We'll set the width to our xScale.bandwidth, which will return the width that it's calculated, including appropriate padding. Our height will be our calculated bar height. Our Xs will be our xScale, and we'll give it our x selector with our data point. This will calculate, from the left to the right, what the specific placement of our bar should be. Our y will be our y value.

[04:36] We'll also supply a stroke, which we'll say is FF6347, a stroke width of three. We'll fill it with a light gray of F5F5F5. If we look at how this renders, we can see that we're rendering seemingly from the bottom, all the way to our largest value of 500 up here.

[05:03] What is actually happening is this y value is this point here, here, here, and here. Then we're taking that minus the height, so that we know that the bar height is going to be our y value here. Subtract that, and that way we have our bar height.

[05:30] This is actually moving our element here, and then rendering the rest of the way down. Our y value, if we look at our y scale, 500 maps to zero. This is the zero coordinate of the y value. We're saying our y value at the max is here, then rendering a full bar height, and then so on and so forth.

[05:55] If we wanted these bars to starting rendering from the top downwards, we can ignore our y value for the y position and switch it to zero. We still use it to calculate the bar height, but now that we have y zero, it's actually rendering everything here, and then rendering the bar height.

[06:15] This illustrates that the y value is just controlling where we start our rendering of our bar height, downwards.

Cory Armbrecht
Cory Armbrecht
~ 6 years ago

Could you tell me the reason for the xSelector (and also ySelector) in this example? I don't understand why you would need to have a selector wrapping the datum that you're going to access anyways:

d => d.x vs d => xSelector(d)

Within xScale(), I don't understand scaleBand().domain(). Shouldn't domain be the length of an array? The x position of the <rect> I would think would be determined by i or data.length, not by a set of numbers like yScale (the numbers of d.y correlate to the heights of the <rect>), but index determines x position or offset, otherwise they wouldn't be spaced evenly. Thanks for any insight here.

Markdown supported.
Become a member to join the discussionEnroll Today