I love small multiples more than anything else.
Instead of one big complicated chart, you just make a lot of small ones. Here’s one from the New York Times about droughts.
Here’s another example from Wikipedia.
Small multiples make information that would usually take animation or many overlapping lines instead become understandable at a glance!
svg
elementsLet’s say you can make a simple line chart using US climate data.
<svg></svg>
<style>.line { fill: none; stroke-width: 1.5px; stroke: #000000;}</style>
<script>
var height = 300, width = 500;
// average per-month highs in Alaska
var title = "Alaska";
// jan, feb, mar, apr, may, etc
var datapoints = [57, 62, 70, 77, 84, 90, 92, 92, 87, 78, 69, 60];
// y_scale: highs between 20 and 110 give us y values between 0 and 300 (height)
// except you do it backwards because it's *distance from the top*
var y_scale = d3.scale.linear().domain([20,110]).range([height, 0])
// x_scale: use the index of the measurement, so 57 is 0, 62 is 1, etc
// this is because it's per-month data, jan=0, dec=11
var x_scale = d3.scale.linear().domain([0,11]).range([0, width])
var line = d3.svg.line()
.x(function(d, i) { return x_scale(i); })
.y(function(d) { return y_scale(d); });
var svg = d3.select("svg")
.attr("width", width)
.attr("height", height)
svg.append("path")
.datum(datapoints)
.attr("class", "line")
.attr("d", line);
</script>
But let’s say we now have like nine different states and we want to display them all at once.
What we usually do when we have multiple data points is take that svg, do a selectAll
, bind our data and add a ton of circle
elements or rect
elements or whatever we’re looking to do. But we want multiple svg
elements, not multiple circle
s!
But really, you just do the same thing.
selectAll
the svgs inside of it.enter
and .append('svg')
, giving you a separate svg for each data point.You’ll want an example, so here you go.
<style>.label { font-size: 10px; } .line { fill: none; stroke-width: 1.5px; stroke: #000000;} svg { border: solid 1px #333; margin: 5px;}</style>
<script>
var height = 50, width = 70;
var datapoints = [
{
'state': 'Alabama',
'measurements': [57, 62, 70, 77, 84, 90, 92, 92, 87, 78, 69, 60]
},
{
'state': 'Alaska',
'measurements': [23, 27, 34, 44, 56, 63, 65, 64, 55, 40, 28, 25]
},
{
'state': 'Arizona',
'measurements': [67, 71, 77, 85, 95, 104, 106, 104, 100, 89, 76, 66]
},
{
'state': 'Arkansas',
'measurements': [51, 55, 64, 73, 81, 89, 92, 93, 86, 75, 63, 52]
},
{
'state': 'California',
'measurements': [54, 60, 65, 71, 80, 87, 92, 91, 87, 78, 64, 54]
},
{
'state': 'Colorado',
'measurements': [45, 46, 54, 61, 72, 82, 90, 88, 79, 66, 52, 45]
},
{
'state': 'Connecticut',
'measurements': [37, 40, 47, 58, 68, 77, 82, 81, 74, 63, 53, 42]
},
{
'state': 'Delaware',
'measurements': [43, 47, 55, 66, 75, 83, 87, 85, 79, 69, 58, 47]
},
{
'state': 'Florida',
'measurements': [64, 67, 74, 80, 87, 91, 92, 92, 88, 81, 73, 65]
}
]
// y_scale: highs between 20 and 110 give us y values between 0 and 300 (height)
// except you do it backwards because it's *distance from the top*
var y_scale = d3.scale.linear().domain([20,110]).range([height, 0]);
// x_scale: use the index of the measurement, so 57 is 0, 62 is 1, etc
// this is because it's per-month data, jan=0, dec=11
var x_scale = d3.scale.linear().domain([0,11]).range([width, 0]);
var line = d3.svg.line()
.x(function(d, i) { return x_scale(i); })
.y(function(d) { return y_scale(d); });
// Treat an svg just like we would a circle - add one for every single data point
var svgs = d3.select("body")
.selectAll("svg")
.data(datapoints)
.enter()
.append('svg')
.attr("width", width)
.attr("height", height);
// Inside of each svg, draw your line
svgs.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d['measurements']);
});
svgs.append("text")
.attr('class','label')
.attr('x', width / 2)
.attr('y', height - 5)
.text( function(d) {
return d['state'];
})
.attr('text-anchor', 'middle')
</script>
Yeah, it’s horrifying looking, but you get my point. If you treat the svg
same as you’d treat a circle
or anything else, you can add tons of stuff inside.