Skip to content

Instantly share code, notes, and snippets.

@armollica
Last active February 14, 2018 22:51
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save armollica/6314f45890bcaaa45c808b5d2b0c602f to your computer and use it in GitHub Desktop.
Save armollica/6314f45890bcaaa45c808b5d2b0c602f to your computer and use it in GitHub Desktop.
Small Multiple Choropleth Map
height: 3260

Small multiples choropleth map. Color shows the annual percent change in the number of manufacturing jobs. Red is a decline, blue is growth.

Three recessions are covered in this timespan: July 1990 to March 1991, March 2001 to November 2001, and December 2007 to June 2009 (see NBER's business cycle dates).

In a real world situation you wouldn't want to have the user's browser do all the computation needed to draw these maps. The maps are rendered in <canvas> so it would be fairly straightforward to pre-render them as images and to serve those instead.

Source: Bureau of Labor Statistics' QCEW program

<html>
<head>
<style>
html {
font-family: monospace;
}
th, .row-header {
font-size: 20px;
font-weight: normal;
}
.row-header {
padding: 20px;
}
</style>
</head>
<body>
<h4 class="loading-text">
Loading... (This takes a long time. Has to render 300,000 tiny polygons.
This would be pre-rendered in a normal situation)
</h4>
<script src="//d3js.org/d3.v3.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script src="https://d3js.org/d3-queue.v2.min.js"></script>
<script>
var queue = d3_queue.queue();
var width = 210,
height = 125;
var colorScale = d3.scale.threshold()
.domain([-0.2, -0.1, -0.025, 0.025, 0.1, 0.2])
.range(["#b2182b", "#ef8a62", "#fddbc7", "#f7f7f7", "#d1e5f0", "#67a9cf", "#2166ac"]);
var projection = d3.geo.albersUsa()
.scale(250)
.translate([width/2, height/2]);
var path = d3.geo.path()
.projection(projection);
var table = d3.select("body").append("table");
queue
.defer(d3.json, "us.json")
.defer(d3.json, "manufacturing.json")
.await(ready);
function ready(error, us, manufacturing) {
if (error) throw error;
var nested = d3.nest()
.key(function(d) { return d.year; })
.key(function(d) { return d.qtr; })
.rollup(function(d) { return d3.map(d, function(d) { return d.fips; })})
.entries(manufacturing);
var counties = topojson.feature(us, us.objects.counties);
counties.features
.forEach(function(feature) {
feature.properties.centroid = path.centroid(feature);
});
table.append("thead").selectAll("th")
.data(["", "Q1", "Q2", "Q3", "Q4"])
.enter().append("th")
.text(function(d) { return d; });
var tr = table.selectAll("tr")
.data(nested, function(d) { return d.key; })
.enter().append("tr");
tr.append("td")
.attr("class", "row-header")
.text(function(d) { return d.key; });
var td = tr.selectAll(".map").data(function(d) { return d.values; })
.enter().append("td")
.attr("class", "map");
var canvases = td.append("canvas")
.attr("width", width)
.attr("height", height)
.each(render);
d3.select(".loading-text").remove();
function render(d) {
var data = d.values;
var context = d3.select(this).node().getContext("2d");
var color = function(d) {
if (data.has(d.id)) {
var value = data.get(d.id).pct_change_emp;
return value ? colorScale(value) : "#fff";
}
return "#fff";
};
// Want the maps to render sequentially. Use setTimeout to give the
// browser a break in between drawing each map.
window.setTimeout(function() {
drawMap(context, color);
}, 500);
}
function drawMap(context, color) {
path.context(context);
context.strokeStyle = "#fff";
context.lineWidth = 0.1;
counties.features.forEach(function(d) {
context.beginPath()
path(d);
context.fillStyle = color(d);
context.fill();
context.stroke();
});
}
}
</script>
</body>
</html>
This file has been truncated, but you can view the full file.
View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment