Layout SVG Elements on a Y Axis with a D3 Band Scale in React

Andy Van Slaars
InstructorAndy Van Slaars

Share this video with your friends

Send Tweet
Published 2 years ago
Updated 2 years ago

A band scale allows us to map a discrete set of values to a continuous range. In this lesson, we'll use a band scale in D3 to take the distinct "region" keys in our sample data and map those to evenly spaced and sized elements on our y-axis. We'll use this band scale to show a bar in the bar chart for each region, setting their size and position based on this scale.

Andy Van Slaars: [0:00] In order to start visualizing multiple data points from our data array here, we're going to need to define a Y scale. Right now, we have the X scale that's going to define the width of the bars.

[0:10] The Y scale is going to be how we lay things out going from top to bottom. We'll start by defining a Y accessor. We can see that the X accessor is grabbing value from our objects while our Y accessor is going to grab regions.

[0:21] I'm just going to scroll down. We'll add a Y accessor right below our X accessor. That's going to take D and grad D.region. Then we're going to go to our chart component and we're going to pass this in as a prop.

[0:46] Now that we have that defined and being passed into our component, let's open up the chart component and let's update our imports. We're going to add a scale band import from D3. We're also going to update our props destructuring here to also grab our Y accessor.

[1:02] We're going to drop down below our X scale. I add a const and I'll call it Y scale. This is going to be a call to our scale band. We're going to call the domain method here just like we did for our X scale.

[1:15] The difference is, instead of giving it two ends of range of values, the band scale needs a set of discrete values. We're going to use data.map, and we're just going to grab all of our regions by passing map our Y accessor.

[1:32] That's going to give us a discrete set of values for our domain. Then we're going to use the range method here to define the pixel range that those values are going to map to. In this case, we're going to go from our bounded height, down to zero.

[1:45] Now that we have the scale defined, let's use it to render our output. I'm going to come into this component here. Instead of this static black rectangle, we're going to map over our data and we're going to draw a rectangle for each data point.

[1:58] Here, I'm just going to add a data.map. In that map, I'm going to accept a single data point. We'll call it a datum. We're going to return our element, which in this case is going to be this black rectangle. We're going to leave the height of 50 pixels for now.

[2:14] Then our width is going to be based on accessing our X value, applying the X scale to it. For that, we're just going to use datum. If I save that, we'll see that we just get one big solid bar. What's happening is, they're all being stacked on top of each other.

[2:30] In order to properly place these, we're going to apply a transform to each one of these rectangles. I'm going to come over here and I'm just going to create a little bit of space to work. I'm going to give this transform prop.

[2:44] For this, I'm going to use string interpolation, and I'm going to apply translate. I'm going to leave the X value at zero. I'm going to apply the Y scale to the Y value of our datum. I'll use the Y accessor and I'm going to pass this datum. I'm going to save the chart component.

[3:09] We'll see that our bars have been positioned on our SVG based on our scales. Right now, each bar is set to 50 pixels because we've hard-coded it. We should calculate that using our scales as well.

[3:19] I'm going to come back up here outside of our return, just below our Y scale, and I'm going to define a new constant. I'm going to call it bandwidth. We'll get that by calling Y scale.bandwidth. Now that we have that value, we can use that and we'll come down into our component.

[3:37] We'll replace this hard-coded 50-pixel value with our bandwidth. If we save this, we'll see that our bands have gotten taller and they're basically filling the space. That width has been calculated based on the number of discrete values and the pixel range that we have available.