This is not a true Demers cartogram; it lacks links between adjacent features. Instead of trying to preserve connectedness, this pseudo-cartogram tries to preserve locality, putting each square as close as possible to its origin without overlapping.
forked from mbostock's block: Pseudo-Demers Cartogram
forked from SpaceActuary's block: Pseudo-Demers Cartogram
forked from SpaceActuary's block: Switchable Cartograms
xxxxxxxxxx
<meta charset="utf-8">
<title>State Choropleth</title>
<style>
body {
font-family: sans-serif;
}
.states {
fill: url(#stripes);
stroke: #fff;
}
text.legendtitle {
font-weight: bold;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script src="//d3js.org/queue.v1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.10.0/d3-legend.min.js"></script>
<script>
console.clear()
var margin = {top: 50, right: 0, bottom: 20, left: 0},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var projection = d3.geo.albersUsa();
// create a geo path - https://github.com/mbostock/d3/wiki/Geo-Paths
var path = d3.geo.path();
// create an svg element
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom),
defs = svg.append("defs"),
svgG = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")" +
"scale(" + Math.min(width / 960, height / 500) + ")");
// Set up a pattern for striping states with missing / no data
var stripes = defs.append("pattern")
.attr("id", "stripes")
.attr("width", 15)
.attr("height", 10)
.attr("patternUnits", "userSpaceOnUse")
.attr("patternTransform", "rotate(45 50 50)")
stripes.append("line")
.attr("stroke", "#d8d8d8")
.attr("stroke-width", 10)
.attr("y2", 20);
// create a container for states
var states = svgG.append("g")
.attr("class", "states");
var colorScale = d3.scale.linear()
.range(["steelblue", "white", "crimson"]);
svgG.append("g")
.attr("class", "legendLinear")
.attr("transform", "translate(" + (width - 150) + "," + (height - 100) + ")");
queue()
.defer(d3.csv, "data.csv")
.defer(d3.json, "us-state-centroids.json")
.defer(d3.json, "us.json")
.await(ready);
function ready(error, data, centroids, us) {
if (error) throw error;
//console.table(data);
colorScale.domain([
d3.max(data, function(d) { return +d["2012D"]; }),
0,
-d3.max(data, function(d) { return +d["2012R"]; })
])
var dataById = d3.map(data, function(d) { return +d.id; });
// fill in all of the states at once
// this uses the "states" class to stripe the background
states.append("path")
.attr("class", "states")
.datum(topojson.feature(us, us.objects.states))
.attr("d", path);
// create paths for each state using the json data
// and the geo path generator to draw the shapes
states.selectAll(".state")
.data(topojson.feature(us, us.objects.states).features
.filter(function(d) { return dataById.has(+d.id); }))
.enter().append("path")
.attr("class", function(d) { return "state " + d.id; })
.style("fill", function(d) {
var stateData = dataById.get(+d.id);
console.log(d.id, stateData.code, stateData,
stateData["2012D"] - stateData["2012R"])
return colorScale(stateData["2012D"] - stateData["2012R"]); })
.attr("d", path);
var legendLinear = d3.legend.color()
.shapeWidth(30)
.cells([55, 30, 5, 0, -5, -20, -38])
.title("Candidate (electoral votes)")
.scale(colorScale);
svgG.select(".legendLinear")
.call(legendLinear);
};
</script>
https://d3js.org/d3.v3.min.js
https://d3js.org/topojson.v1.min.js
https://d3js.org/queue.v1.min.js
https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.10.0/d3-legend.min.js