Hi, I'm Nicholas Johnson!

software engineer / trainer / AI enthusiast


Up till now we have been munging our data into shape manually. If we have data in the range 0 to 10, we have simply multiplied the value by 10 to get a percentage.

Instead it would be better if we could fit our data into a range. We can achieve this with a d3 scale function to normalise our data within a range.

The d3.scale object

d3.scale is an object full of scale function generators. Open it up in a console and you can see all the scales available to you. These are:

  • identity
  • linear
  • log
  • ordinal
  • pow
  • quantile
  • quantize
  • sqrt
  • threshold

Linear scale

We can create a simple linear scale using the linear function:

let scale = d3.scale.linear();

Once made we can pass values to it:

scale(5); // returns 5
scale(99); // returns 99


We can make this more useful by setting a domain. A domain is the minimum and maximum values the data can have.

let scale = d3.scale.linear().domain([0, 10]);

This will now normalise data between 0 and 1:

scale(0); // returns 0
scale(5); // returns 0.5
scale(10); // returns 1

Setting the domain automatically with min and max

We can set the domain automatically with min and max. Min will give us the lowest value in a data set. Max will give us the highest:

let data = [5, 7, 6, 3, 6];

let min = d3.min(data); // returns 3
let max = d3.max(data); // returns 7

let scale = d3.scale.linear().domain([min, max]);

Now when we call this function, 3 will be the lowest value, and 7 will be the highest:

scale(3); // returns 0
scale(7); // returns 1
scale(6); // returns 0.75

Setting a range

Our data so far has been normalised between 0 and 1. We can normalise to a different range that corresponds to the size of our graph:

Say we make an svg element like this:

let width = 300,
  height = 200;

d3.select("body").append("svg").attr("width", width).attr("height", height);

We can modify our scale function to normalise our data to fit in this graph using the range function:

let scale = d3.scale.linear().domain([min, max]).range([0, width]);

scale(3); // returns 0
scale(5); // returns 150
scale(7); // returns 300

Padding with scales

We can use scales to add padding to our SVG element so the data points are not hard against the edge. Create a padding variable and then use it to adjust your range:

let padding = 50;

let scale = d3.scale
  .domain([min, max])
  .range([padding, width - padding]);

Inverting your chart

You can also invert a chart using scales, just swap the range values over:

let scale = d3.scale.linear().domain([min, max]).range([width, 0]);

Exercise - Add a scale to your graph

Choose your favourite graph and modify it to work with a scale. Add a little padding using a padding variable so your elements don’t press against the edge.

Exercise - Invert your graph

Use a scale to invert your graph. Notice how this simplifies quite a lot of the maths to do with positioning elements.

Exercise - Log Scale

Modify your graph to use a log scale. This involves changing a single word in your code. Nice eh?