Monogram mark of Manish Shivanandhan
Manish Shivanandhan
Full Stack Web, Deep Learning & D3 Visualizations Engineer

D3 scales and axes

D3 and data visualisation · applies to: D3, chart construction · last updated 2016-05-27

A scale is a plain function from data space to pixel space, and an axis is that function drawn.

Domain and range

A scale carries two intervals. The domain is the span of the data, in the data's own units. The range is the span of the drawing surface, in pixels. Calling the scale with a data value returns the pixel position; calling its inverse turns a mouse position back into a data value.

Because it is only a function, a scale can be built and tested without any drawing at all, which is the fastest way to find out whether a chart is broken in its arithmetic or in its markup.

The inverted vertical range

Screen coordinates increase downwards while values increase upwards. A vertical scale therefore takes a range running from the chart height down to zero, not from zero up. Getting this backwards produces a chart that is correct in every respect except that it is upside down, which is why it is worth checking first.

Axes and margins

An axis generator reads a scale's domain, picks readable tick values, and emits the ticks, labels and domain line. It draws at the origin of whatever group it is called on, so the group has to be moved to the edge of the plotting area.

That plotting area is the surface minus a margin on each side. Reserving the margin first and treating everything inside it as the drawing space avoids the usual problem of axis labels being clipped at the edge.

Setting up a plot area

  1. Choose margins large enough for the longest tick label plus the axis title.
  2. Compute inner width and inner height by subtracting those margins.
  3. Build a horizontal scale with the data extent as domain and zero to inner width as range.
  4. Build a vertical scale with the value extent as domain and inner height down to zero as range.
  5. Append a group translated by the left and top margins, and draw everything inside it.
  6. Call the axis generators on their own groups, positioned at the bottom and left edges of that inner area.
var y = d3.scaleLinear()
  .domain([0, d3.max(data, function (d) { return d.value; })])
  .range([innerHeight, 0]);   // note the order

The vertical range runs downwards

Worth knowingIf every point lands at the same coordinate, the domain was built from an empty or wrongly named field and collapsed to a single value.

Return to D3 and data visualisation