Skip to content

Instantly share code, notes, and snippets.

@recursionbane
Forked from mbostock/.block
Created February 27, 2017 16:41
Show Gist options
  • Save recursionbane/66377d3382e963d8a0e94764bde18de7 to your computer and use it in GitHub Desktop.
Save recursionbane/66377d3382e963d8a0e94764bde18de7 to your computer and use it in GitHub Desktop.
Square Grid
license: gpl-3.0

A simple and effective form for visualizing magnitude is this gridded layout of colored squares. Each individual square represents one unit; each small row represents ten units; the small rows are grouped into ten, representing one hundred; lastly, ten groups per large row represents one thousand. This arrangement affords quick and natural reading of exact counts by powers of ten.

For an example of this technique in practice, see Randall Munroe’s Radiation Dose Chart.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
.cells {
fill: #aaa;
}
.label {
text-anchor: start;
font: 24px sans-serif;
}
</style>
<svg width="960" height="990"></svg>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var formatNumber = d3.format(",d");
var svg = d3.select("svg");
var width = +svg.attr("width"),
height = +svg.attr("height");
var groupSpacing = 3,
cellSpacing = 1,
cellSize = Math.floor((width - 11 * groupSpacing) / 100) - cellSpacing,
offset = Math.floor((width - 100 * cellSize - 90 * cellSpacing - 11 * groupSpacing) / 2);
var updateDuration = 125,
updateDelay = updateDuration / 500;
var cell = svg.append("g")
.attr("class", "cells")
.attr("transform", "translate(" + offset + "," + (offset + 30) + ")")
.selectAll("rect");
var label = svg.append("text")
.attr("class", "label");
function update(n1) {
var n0 = cell.size();
cell = cell
.data(d3.range(n1));
cell.exit().transition()
.delay(function(d, i) { return (n0 - i) * updateDelay; })
.duration(updateDuration)
.attr("width", 0)
.remove();
cell.enter().append("rect")
.attr("width", 0)
.attr("height", cellSize)
.attr("x", function(i) {
var x0 = Math.floor(i / 100) % 10, x1 = Math.floor(i % 10);
return groupSpacing * x0 + (cellSpacing + cellSize) * (x1 + x0 * 10);
})
.attr("y", function(i) {
var y0 = Math.floor(i / 1000), y1 = Math.floor(i % 100 / 10);
return groupSpacing * y0 + (cellSpacing + cellSize) * (y1 + y0 * 10);
})
.transition()
.delay(function(d, i) { return (i - n0) * updateDelay; })
.duration(updateDuration)
.attr("width", cellSize);
label
.attr("x", offset + groupSpacing)
.attr("y", offset + groupSpacing)
.attr("dy", ".71em")
.transition()
.duration(Math.abs(n1 - n0) * updateDelay + updateDuration / 2)
.ease("linear")
.tween("text", function() {
var i = d3.interpolateNumber(n0, n1);
return function(t) {
this.textContent = formatNumber(Math.round(i(t)));
};
});
}
(function interval() {
update(Math.floor(Math.random() * 100 * 100));
setTimeout(interval, updateDelay * 100 * 100 + updateDuration + 1000);
})();
d3.select(self.frameElement).style("height", height + "px");
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment