Skip to content

Instantly share code, notes, and snippets.

@mbostock
Last active February 13, 2020 18:29
  • Star 2 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save mbostock/4055908 to your computer and use it in GitHub Desktop.
Non-Contiguous Cartogram
license: gpl-3.0
redirect: https://observablehq.com/@d3/non-contiguous-cartogram

Unlike choropleth maps, cartograms encode data using area rather than color, resulting in distorted geographic boundaries. In this example, states are rescaled around their centroid, preserving local shape but not topology. Inspired by Zachary Johnson. Non-continguous cartogram design invented by Judy Olsen. U.S. state and county boundaries from the U.S. Census Bureau, simplified using GDAL and MapShaper.

<!DOCTYPE html>
<meta charset="utf-8">
<title>Non-Contiguous Cartogram</title>
<style>
.land {
fill: #fff;
stroke: #ccc;
}
.state {
fill: #ccc;
stroke: #666;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>
// Ratio of Obese (BMI >= 30) in U.S. Adults, CDC 2008
var valueById = [
NaN, .187, .198, NaN, .133, .175, .151, NaN, .100, .125,
.171, NaN, .172, .133, NaN, .108, .142, .167, .201, .175,
.159, .169, .177, .141, .163, .117, .182, .153, .195, .189,
.134, .163, .133, .151, .145, .130, .139, .169, .164, .175,
.135, .152, .169, NaN, .132, .167, .139, .184, .159, .140,
.146, .157, NaN, .139, .183, .160, .143
];
var path = d3.geo.path();
var svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500);
d3.json("/mbostock/raw/4090846/us.json", function(error, us) {
if (error) throw error;
svg.append("path")
.datum(topojson.feature(us, us.objects.land))
.attr("class", "land")
.attr("d", path);
svg.selectAll(".state")
.data(topojson.feature(us, us.objects.states).features)
.enter().append("path")
.attr("class", "state")
.attr("d", path)
.attr("transform", function(d) {
var centroid = path.centroid(d),
x = centroid[0],
y = centroid[1];
return "translate(" + x + "," + y + ")"
+ "scale(" + Math.sqrt(valueById[d.id] * 5 || 0) + ")"
+ "translate(" + -x + "," + -y + ")";
})
.style("stroke-width", function(d) {
return 1 / Math.sqrt(valueById[d.id] * 5 || 1);
});
});
</script>
@johnreynolds
Copy link

Looking at this, it occurred to me that it might be interesting to scale each state by its population in addition to centering on the centroid.

@eatAsnack
Copy link

Yes, the ability to zoom states forward on the z axis would be remarkable, and you could tie this to dimensions such as populations, incarcerated population, metrics for total lobby dollars received are available through the opensecrets.org api. I would be glad to assist.

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