SVG-based Sparkline with d3.js

DECEMBER 19, 2013

This is a tutorial of how to create various SVG based sparklines with d3.js. Sparkline, a tiny line chart, is often very effective and visually appealing, especially for today's small screen devices.


Yale University Professor, Edward Tufte, invented sparkline that is often seen in many web sites these days. I've attended one of his courses many years back and been fascinated with the history and depth of information design since. This is his quote about sparkline:

A sparkline is a small intense, simple, word-sized graphic with typographic resolution. Sparklines mean that graphics are no longer cartoonish special occasions with captions and boxes, but rather sparkline graphic can be everywhere a word or number can be: embedded in a sentence, table, headline, map, spreadsheet, graphic.

Edward Tufte


Using d3.js, we can fairly easily draw SVG-based sparklines. This is 2013 historical stock prices for Google $1084.75. And this is for Facebook $55.57. And this is for Apple $550.77. Each sparkline has 244 data points, but it's condensed very nicely.


In this tutorial, I downloaded historical stock prices from Google Finance. You can download CSV files from there. The file contains many extra columns, and I dropped all columns but Date and Close Price. Here is my first attempt of sparkline:

<style>
.sparkline {
  fill: none;
  stroke: #000;
  stroke-width: 0.5px;
}
</style>
...
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 100;
var height = 25;
var x = d3.scale.linear().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var parseDate = d3.time.format("%b %d, %Y").parse;
var line = d3.svg.line()
             .x(function(d) { return x(d.date); })
             .y(function(d) { return y(d.close); });

function sparkline(elemId, data) {
  data.forEach(function(d) {
    d.date = parseDate(d.Date);
    d.close = +d.Close;
  });
  x.domain(d3.extent(data, function(d) { return d.date; }));
  y.domain(d3.extent(data, function(d) { return d.close; }));

  d3.select(elemId)
    .append('svg')
    .attr('width', width)
    .attr('height', height)
    .append('path')
    .datum(data)
    .attr('class', 'sparkline')
    .attr('d', line);
}

d3.csv('/csv/goog.csv', function(error, data) {
  sparkline('#spark_goog', data);
});
...
</script>


The code above produces a sparkline for Google like this, but if you look at it carefully, it looks edgy. This is because I didn't set any interpolation for the line. Let's set a basis interpolation.

var line = d3.svg.line()
             .interpolate("basis")
             .x(function(d) { return x(d.date); })
             .y(function(d) { return y(d.close); });      


With basis interpolation, new sparkline looks like this. Do you see it looks a little smoother now? Depending on your data representation, you can set different interpolation modes.


Lastly, let's plot a little red circle at the end of line. You can just add a circle element, but you want to add some margin at top, bottom and right in order to avoid cutting off a circle. Here is the modified code:

<style>
.sparkline {
  fill: none;
  stroke: #000;
  stroke-width: 0.5px;
}
.sparkcircle {
  fill: #f00;
  stroke: none;
}
</style>
...
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 100;
var height = 25;
var x = d3.scale.linear().range([0, width - 2]);
var y = d3.scale.linear().range([height - 4, 0]);
var parseDate = d3.time.format("%b %d, %Y").parse;
var line = d3.svg.line()
             .interpolate("basis")
             .x(function(d) { return x(d.date); })
             .y(function(d) { return y(d.close); });

function sparkline(elemId, data) {
  data.forEach(function(d) {
    d.date = parseDate(d.Date);
    d.close = +d.Close;
  });
  x.domain(d3.extent(data, function(d) { return d.date; }));
  y.domain(d3.extent(data, function(d) { return d.close; }));

  var svg = d3.select(elemId)
              .append('svg')
              .attr('width', width)
              .attr('height', height)
              .append('g')
              .attr('transform', 'translate(0, 2)');
  svg.append('path')
     .datum(data)
     .attr('class', 'sparkline')
     .attr('d', line);
  svg.append('circle')
     .attr('class', 'sparkcircle')
     .attr('cx', x(data[0].date))
     .attr('cy', y(data[0].close))
     .attr('r', 1.5);  
}

d3.csv('/csv/goog.csv', function(error, data) {
  sparkline('#spark_goog', data);
});
...
</script>


This will produce the first examples you saw at the top, like this $1084.75. If you are interested in what you should or shouldn't do in sparkline, I would recommend you to check out Mr. Tufte's lecture.


Related Posts

Flight Animation with d3.js

This is a step by step tutorial of how to create flight animation on the map, using d3.js Geo and Transition. Everything is rendered in SVG, and you can learn from creating a world map, plotting airports to animating flying planes.

Responsive d3.js

It's increasingly important to make d3.js charts responsive for touch-based devices such as mobile and tablet. While this approach doesn't solve everything, it's one way of making SVG based charts dynamic and responsive.

Prettyprint in Bootstrap 3

Here is how to pretty print code, using google code prettify and Bootstrap 3.