How to create chart axes using D3's axis module. This article covers axis orientation, transitions, number of ticks, custom tick values, tick formatting and tick size.
One of the most useful D3 modules (especially when creating bar, line and scatter charts) is the axis module which draws axes:
How to create an axis
You need two things to create a D3 axis:
- an SVG element to contain the axis (usually a
g
element) - a D3 scale function
A D3 scale function has a domain and range (see the scales chapter). The domain specifies the input extent (for example [0, 100]
) and the range defines the output extent (for example [0, 1000]
) of the scale.
When a D3 scale function is used to define an axis, the scale domain determines the minimum and maximum tick values and the range determines the length of the axis.
To create an axis:
- make an axis generator function using
d3.axisBottom
,d3.axisTop
,d3.axisLeft
ord3.axisRight
(and pass in your scale function) - select the container element and pass the axis generator into
.call
Here's a basic example:
<svg width="600" height="100">
<g transform="translate(20, 50)"></g>
</svg>
let scale = d3.scaleLinear().domain([0, 100]).range([0, 500]);
let axis = d3.axisBottom(scale);
d3.select('svg g')
.call(axis);
We cover
.call
in the selections chapter. In brief you pass a function into.call
. The function's first parameter is a selection with which the function can operate on. An axis generator (theaxis
variable in the above example) appendspath
,line
andtext
elements (that represent the axis) to the selection.
The axis can be positioned by transforming the axis's container. In the above example, the
g
element that contains the axis is translated by(20, 50)
.
Axis orientation
d3.axisBottom
, d3.axisTop
, d3.axisLeft
and d3.axisRight
are used to generate axes that are suitable for the bottom, top, left and right of a chart, respectively:
<svg width="500" height="500">
<g id="left" transform="translate(30, 40)"></g>
<g id="right" transform="translate(450, 40)"></g>
<g id="top" transform="translate(40, 30)"></g>
<g id="bottom" transform="translate(40, 450)"></g>
</svg>
let scale = d3.scaleLinear().domain([0, 100]).range([0, 400]);
let axisLeft = d3.axisLeft(scale);
let axisRight = d3.axisRight(scale);
let axisTop = d3.axisTop(scale);
let axisBottom = d3.axisBottom(scale);
d3.select('#left').call(axisLeft);
d3.select('#right').call(axisRight);
d3.select('#top').call(axisTop);
d3.select('#bottom').call(axisBottom);
Scale types
You can pass in any scale function that has numeric output. This includes scaleLinear
, scaleSqrt
, scaleLog
, scaleTime
, scaleBand
and scalePoint
.
Here's an example using each scale type:
scaleBand
is useful for bar charts. Read more here.
Transitions
If the scale's domain changes, the axis can be updated by calling .call(axis)
again:
d3.select('svg g')
.call(axis);
You can also add a call to .transition
to make the axis animate:
d3.select('svg g')
.transition()
.call(axis);
Axis configuration
You can configure axes in the following ways:
- specify the number of ticks OR specify the tick values
- specify the format of the tick label (for example, add a percentage sign)
- specify the tick size
Number of ticks
You can use the .ticks
method to specify how many ticks the axis has:
let scale = d3.scaleLinear().domain([0, 100]).range([0, 500]);
let axis = d3.axisBottom(scale);
axis.ticks(20);
d3.select('svg g')
.call(axis);
D3 tries to use as many ticks as requested, but in some cases it'll use more or less in order for the tick values to be round numbers.
The axis uses its scale function's
.ticks
method to generate an array of tick values.
Tick values
You can specify the axis's tick values by passing an array of tick values into the .tickValues
method:
let scale = d3.scaleLinear().domain([0, 100]).range([0, 500]);
let axis = d3.axisBottom(scale);
axis.tickValues([0, 25, 50, 75, 100]);
d3.select('svg g')
.call(axis);
Tick label formatting
You can format the tick label in two ways.
The first is to use the .ticks
method and pass in a format string as the second argument:
let scale = d3.scaleLinear().domain([0, 100]).range([0, 500]);
let axis = d3.axisBottom(scale);
axis.ticks(4, "$.2f");
d3.select('svg g')
.call(axis);
We've already seen that the first argument of
.ticks
is the number of ticks. You can pass innull
if you want to use the default number of ticks.
The format string is powerful and is described in depth in the d3-format section of the official documentation.
The second approach is to pass a formatting function into the .tickFormat
method. The function accepts a value and outputs a formatted value.
In this example we add a % symbol to each tick value:
let scale = d3.scaleLinear().domain([0, 100]).range([0, 500]);
let axis = d3.axisBottom(scale);
axis.ticks(4)
.tickFormat(function(d) {
return d + "%";
});
d3.select('svg g')
.call(axis);
Tick size
The length of the ticks can be set using the .tickSize
method. You can also set the distance between the tick and the tick label using .tickPadding
:
let scale = d3.scaleLinear().domain([0, 100]).range([0, 500]);
let axis = d3.axisBottom(scale)
.tickPadding(10)
.tickSize(10);
d3.select('svg g')
.call(axis);
The axis is made up of a path
element (that looks like a long square bracket and represents two end ticks and the main axis line) and line
elements that represent each tick (including the end ticks).
You can set the length of the end ticks of the path
element using .tickSizeOuter
and the length of the line
elements using .tickSizeInner
. (I'm not sure of when this might be used.)
You can also create grid lines by setting the tick size to your chart width (or height). In this example we use axisLeft
and set the tick size to 500. The axis also has a transform of translate(520, 20)
and it's path
element that represents the main axis is hidden. (If the main axis was visible, you'd see it to the right of the grid lines.)