Build a bottom axis


In the previous lesson, we learned how to manage margins effectively in our chart. But now that there is some free space, we need to actually draw the axes!

This lesson explores how to create a AxisBottom react component that draws a bottom axis.

Members only
10 minutes read

Decomposing an axis

Now that you're comfortable with React and SVG, look at an axis with fresh eyes. What seems complex is actually a handful of simple pieces:

A long horizontal line, a few short vertical lines (the ticks), and a few text elements (the tick labels). That's it!

If you had to build a BottomAxis component from scratch, how would you do it? What props would it need?

Quick scaleLinear() refresher

You already know scaleLinear() from the scales module. The code below should feel familiar — if not, it's worth a quick review before continuing!

const xScale = d3.scaleLinear()
  .domain([0, 100])
  .range([0, 500]);

console.log(xScale(0))    // 0
console.log(xScale(100))  // 500

What I haven't mentioned yet is that xScale comes with a few extra methods that are very handy for building axes:

  • xScale.range() returns the range of the scale, which is [0, 500] in this case.
  • xScale.domain() provides the input domain of the scale ([0, 100])
  • xScale.ticks(10) generates an array of approximately 10 evenly spaced values along the axis. It's smart enough to pick nicely rounded numbers, which is a lifesaver.

These 3 methods are a game changer: pass an xScale to our Axis component, and it has everything it needs to draw itself.

How many ticks?

There's a subtle challenge when building an axis: picking a good number of ticks.

Imagine your data goes from 0 to 100. Two evenly-spaced ticks would land at 33.333 and 66.666 — ugly! Three ticks give you 0, 50, and 100 — much cleaner.

Fortunately, D3's ticks() function handles this for you. It picks a sensible number of ticks close to the one you asked for:

xScale.ticks(2)  // [0, 50, 100]
xScale.ticks(5)  // [0, 20, 40, 60, 80]
xScale.ticks(9)  // [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
xScale.ticks(10) // [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

Notice how .ticks() doesn't always return the exact count you asked for. It finds the closest value that produces clean, round numbers — so your axis always looks polished.

Let's draw!

We know where the ticks go. All that's left is drawing a horizontal line and a small tick + label at each position.

Here's a minimal sandbox that does exactly that. Read through the code — it's shorter than you might expect:

import { scaleLinear } from "d3";

const MARGIN = { top: 30, right: 30, bottom: 50, left: 50 };
const TICK_LENGTH = 8;

const width = 700;
const height = 200;

export default function App() {
  const boundsWidth = width - MARGIN.right - MARGIN.left;

  const xScale = scaleLinear().domain([0, 100]).range([0, boundsWidth]);

  return (
    <svg width={width} height={height}>
      <g transform={`translate(${MARGIN.left}, ${MARGIN.top})`}>
        {/* Main horizontal line */}
        <line
          x1={0}
          x2={boundsWidth}
          y1={0}
          y2={0}
          stroke="black"
          strokeWidth={0.5}
        />

        {/* Ticks and Labels */}
        {xScale.ticks(10).map((value) => (
          <g key={value} transform={`translate(${xScale(value)}, 0)`}>
            <line y2={TICK_LENGTH} stroke="currentColor" />
            <text
              style={{
                fontSize: "10px",
                textAnchor: "middle",
                transform: "translateY(20px)",
              }}
            >
              {value}
            </text>
          </g>
        ))}
      </g>
    </svg>
  );
}

Oh no! 😱

It seems like you haven't enrolled in the course yet!

Join many other students today and learn how to create bespoke, interactive graphs with d3.js and React!

Enrollment is currently closed. Join the waitlist to be notified when doors reopen:

Or Login