Drawing axis in d3.js





This is document gives a few insights on how to draw axis with d3.js. Different scale types are described first, followed by customization possibilities. It is composed by several interactive examples, allowing to play with the code to understand better how it works.

Basic linear axis with scaleLinear()


Let's start with the most common type of axis: the linear axis. Basically, the idea is to map a numeric variable to the axis. It is used in most of chart types, like scatterplot or histogram.

Here is the code allowing to add a linear axis in a div that has the id res (html code not shown here).

// create svg element
var svg = d3.select("#res")
  .append("svg")
    .attr("width", 1000)

// Create the scale
var x = d3.scaleLinear()
    .domain([0, 100])         // This is what is written on the Axis: from 0 to 100
    .range([100, 800]);       // This is where the axis is placed: from 100px to 800px

// Draw the axis
svg
  .append("g")
  .attr("transform", "translate(0,50)")      // This controls the vertical position of the Axis
  .call(d3.axisBottom(x));




Log scale with scaleLog()


Very similar to linear scales above,but applies a logarithmic transform to the input domain value before the output range value is computed.

Note: log(0)=-∞, thus the domain must be strictly positive or strictly negative.

// create svg element
var svg = d3.select("#log_demo")
  .append("svg")
  .attr("width", 1000)
  .attr("height", 200)

// Create the scale
var x = d3.scaleLog()
    .domain([1,1000])         // This is what is written on the Axis: from 0 to 100
    .range([100, 800])       // This is where the axis is placed: from 100 px to 800px
    .base(10)

// Draw the axis
svg
  .append("g")
  .attr("transform", "translate(0,150)")      // This controls the vertical position of the Axis
  .call(d3.axisBottom(x).tickFormat(d3.format(".2")))




Categoric axis with scalePoint()


Here is the Javascript code allowing to add a linear axis in a div that has the id 'res'.

// create svg element
var svg = d3.select("#ordinal_demo")
  .append("svg")
  .attr("width", 1000)
  .attr("height", 200)

// Create the scale
var x = d3.scalePoint()
    .domain(["A", "B", "C", "D", "E"])         // This is what is written on the Axis: from 0 to 100
    .range([100, 800]);       // This is where the axis is placed: from 100 px to 800px

// Draw the axis
svg
  .append("g")
  .attr("transform", "translate(0,150)")      // This controls the vertical position of the Axis
  .call(d3.axisBottom(x));

// Add 1 circle for the group B:
svg
  .append("circle")
  .attr("cx", x("B"))
  .attr("cy", 50)
  .attr("r", 8)



Categoric axis with scaleBand


The scaleBand() function is ideal to build categorical axis. It is thus useful for common charts like barplot or boxplot.

Here is the Javascript code allowing to add a categoric axis in a div that has the id 'res'.

// create svg element
var svg = d3.select("#band_demo")
  .append("svg")
    .attr("width", 1000)
    .attr("height", 300)

// Create the scale
var x = d3.scaleBand()
    .domain(["A", "B", "C", "D", "E"])       // This is what is written on the Axis: from 0 to 100
    .range([100, 800])                       // This is where the axis is placed: from 100 px to 800px
    .padding([0.8])                          // Goes between 0 and 1. Default is 0

// Draw the axis
svg
  .append("g")
  .attr("transform", "translate(0,250)")      // This controls the vertical position of the Axis
  .call(d3.axisBottom(x));

// Add one bar for group C:
svg
  .append("rect")
    .attr("x", x("C") )
    .attr("y",100)
    .attr("height", 150)
    .attr("width", x.bandwidth() )
    .style("fill", "#69b3a2")
    .style("opacity", 0.5)



Vertical axis with axisLeft


All the scale described above can be set vertically.

// create svg element
var svg = d3.select("#vertical")
  .append("svg")
    .attr("width", 1000)
    .attr("height", 300)

// Create the scale
var y = d3.scaleLinear()
    .domain([0, 100])         // This is what is written on the Axis: from 0 to 100
    .range([290, 10]);         // Note it is reversed

// Draw the axis
svg
  .append("g")
  .attr("transform", "translate(50,0)")      // This controls the vertical position of the Axis
  .call(d3.axisLeft(y));


Rotate and custom axis labels


It is sometimes useful to rotate the labels of an axis, especially when this labels are quite long.

// create svg element
var svg = d3.select("#rotate")
  .append("svg")
    .attr("width", 1000)
    .attr("height", 300)

// Create the scale
var x = d3.scaleBand()
    .domain(["Long name", "Another One", "Here", "And this is", "The end", "ouuuu", "not yet"])         // This is what is written on the Axis: from 0 to 100
    .range([0, 800]);         // Note it is reversed

// Draw the axis
svg
  .append("g")
  .attr("transform", "translate(100,100)")      // This controls the rotate position of the Axis
  .call(d3.axisBottom(x))
  .selectAll("text")
    .attr("transform", "translate(-10,10)rotate(-45)")
    .style("text-anchor", "end")
    .style("font-size", 20)
    .style("fill", "#69a3b2")


Axis titles


Axis titles aren't built-in to D3's axis component, but are essential for a chart. You can add titles yourself simply by adding an svg text element. As shown in the chart below:

// set the dimensions and margins of the graph
var margin = {top: 20, right: 20, bottom: 40, left: 60},
    width = 460 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

// create svg element, respecting margins
var svg = d3.select("#title")
  .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");

// Add X axis
var x = d3.scaleLinear().domain([0, 100]).range([0, width]);
svg
  .append("g")
  .attr("transform", "translate(0," + height + ")")
  .call(d3.axisBottom(x));

// Add Y axis
var y = d3.scaleLinear().domain([0, 100]).range([ height, 0]);
svg
  .append("g")
  .call(d3.axisLeft(y));

// Add X axis label:
svg.append("text")
    .attr("text-anchor", "end")
    .attr("x", width)
    .attr("y", height + margin.top + 20)
    .text("X axis title");

// Y axis label:
svg.append("text")
    .attr("text-anchor", "end")
    .attr("transform", "rotate(-90)")
    .attr("y", -margin.left+20)
    .attr("x", -margin.top)
    .text("Y axis title")



Note: The Y axis title uses a 90° rotation to be readable. It causes the whole coordinate system to rotate. Thus x and y attributes for positioning are really tricky to set up properly.

Note: Check the way margins are handled in this example. This is a very common way to proceed in d3.js, as described in this post.



Other usual customization


This is my cheat sheet for usual customization I perform on my charts:

Remove ticks
svg.append("g")
  .call(d3.axisBottom(x).tickSize(0))

Control which ticks are written
svg.append("g")
  .call(d3.axisBottom(x).tickValues(["A", "B", "C"]))

Control the number of ticks approximatively
var yAxis = d3.svg.axis().scale(y)
    .orient("left").ticks(5);

Remove the last tick of the axis
  svg.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x).tickSizeOuter(0))

Remove the main bar of the axis
  svg.append("g")
    .call(d3.axisBottom(x))
    .select(".domain").remove()

Change axis color (this is .css code)
  .yAxis path {
    stroke: #B8B8B8;
  }



Selection of blocks