Adding Gridlines to a Chart with d3

Updated Apr 7, 2019

While gridlines are often frowned upon as chart junk there may be situations where they can assist in data interpretation. With d3 gridlines are easily created using axes and specifying tick sizes to match the chart’s width or height. Here we’ll create a simple x-y plot with gridlines:

To get started we import d3 dependencies and create the main SVG element. Here the SVG is attached to an existing element with an id “grid”:

Getting started Copy
import {
  axisBottom  as d3_axisBottom,
  axisLeft    as d3_axisLeft,
  scaleLinear as d3_scaleLinear,
  select      as d3_select
from 'd3';
const WIDTH        = 400;
const HEIGHT       = 300;
const MARGIN       = { top: 10, right: 10, bottom: 20, left: 30 };
const INNER_WIDTH  = WIDTH - MARGIN.left - MARGIN.right;
const INNER_HEIGHT = HEIGHT - MARGIN.top - MARGIN.bottom;
const svg = d3_select('#grid').append('svg')
  .attr('width', WIDTH)
  .attr('height', HEIGHT)
  .append('g')
    .attr('transform''translate(' + MARGIN.left + ',' + MARGIN.top + ')');

Next we create our x and y scales and the axes. Two sets of axes are created: xAxis and yAxis to provide the labels and xAxisGrid and yAxisGrid to provide the grids. Note that both axes sets use the same scales:

Scales and axes Copy
const x         = d3_scaleLinear().domain([01]).range([0, INNER_WIDTH]);
const y         = d3_scaleLinear().domain([01]).range([INNER_HEIGHT, 0]);
const xAxis     = d3_axisBottom(x).ticks(10);
const yAxis     = d3_axisLeft(y).ticks(10);
const xAxisGrid = d3_axisBottom(x).tickSize(-INNER_HEIGHT).tickFormat('').ticks(10);
const yAxisGrid = d3_axisLeft(y).tickSize(-INNER_WIDTH).tickFormat('').ticks(10);

The grid axes are created on lines 6 and 7. Passing the negative chart height and width to the tickSize functions ensures that the axis lines will span across the chart. Passing an empty string to tickFormat ensures that tick labels aren’t rendered. The ticks function specifies the number of tick marks, here set to 10 to equal the count on the main axes. The last step is to render the axes:

Render axes Copy
// Create grids.
svg.append('g')
  .attr('class''x axis-grid')
  .attr('transform''translate(0,' + INNER_HEIGHT + ')')
  .call(xAxisGrid);
svg.append('g')
  .attr('class''y axis-grid')
  .call(yAxisGrid);
// Create axes.
svg.append('g')
  .attr('class''x axis')
  .attr('transform''translate(0,' + INNER_HEIGHT + ')')
  .call(xAxis);
svg.append('g')
  .attr('class''y axis')
  .call(yAxis);

The grids are attached first so they render beneath the main axes. The above will yield black gridlines but they can easily be styled using CSS to match the example at top:

CSS Copy
.axis-grid line {
  stroke: #def;
}

That’s it.

Comments Leave a comment

  • Sample
    https://codepen.io/jonclawsonmeasurabl/pen/KKwgNRd?editors=0010
  • Visit0r
    Clean and clear solution, works great!

Leave a comment