An adaptation of the NPR hexgrid that sets hexagon size in play as a thematic variable.
Still needs a legend, but:
xxxxxxxxxx
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://d3js.org/d3-geo-projection.v2.min.js"></script>
<style>
body { background-color: #fff; }
</style>
<svg id="cartogram" width="800" height="500"></svg>
<script>
// The svg
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
// Map and projection
var projection = d3.geoMercator()
.scale(600) // This is the zoom
.translate([1500, 750]); // You have to play with these values to center your map
// Path generator
var path = d3.geoPath()
.projection(projection)
// Colors
var lowColor = '#ffffff'
var highColor = '#bc2a66'
// load in the data
d3.queue()
.defer(d3.json, "us_states_hexgrid.geojson")
.defer(d3.csv, "sn.csv")
.await(ready);
function ready(error, geo, sn) {
if (error) throw error;
// get min/max of everything
var getArray = function(data,name) {
var dataArray = [];
for (var d = 0; d < data.length; d++) {
dataArray.push(parseInt(data[d][name]))
}
return dataArray
}
var min1 = d3.min(getArray(sn,'population'))
var max1 = d3.max(getArray(sn,'population'))
var min2 = d3.min(getArray(sn,'avg_sn'))
var max2 = d3.max(getArray(sn,'avg_sn'))
// create color scale
var colorRamp = d3.scaleSqrt()
.domain([min2,max2])
.range([lowColor,highColor])
// Join geojson and CSV (gotta be a better way of doing this)
for (var i = 0; i < sn.length; i++) {
// Grab State Name
var dataState = sn[i].state;
// Grab grouped record count
var dataPop = sn[i].population;
var dataSn = sn[i].avg_sn
// Find the corresponding state inside the GeoJSON
for (var j = 0; j < geo.features.length; j++) {
var geoState = geo.features[j].properties.abbrv;
if (dataState == geoState) {
// Copy the data value into the JSON
geo.features[j].properties.population = parseInt(dataPop);
geo.features[j].properties.avg_sn = parseInt(dataSn);
// Stop looking through the JSON
break;
}
}
}
// Draw the scaled features
svg.append("g")
.selectAll("path")
.data(geo.features)
.enter()
.append("path")
.attr("fill", function(d) { return colorRamp(d.properties.avg_sn) || 'rgba(255,255,255,0.2)' })
.attr("d", path)
.attr("stroke", "rgba(100,100,100,0.9)")
// create resize scale (via https://bl.ocks.org/rveciana/5928736)
.attr("transform", function(d) {
scale_factor = Math.sqrt(d.properties.population/(max1-min1));
var centroid = path.centroid(d),
x = centroid[0],
y = centroid[1];
return "translate(" + x + "," + y + ")"
+ "scale(" + scale_factor + ")"
+ "translate(" + -x + "," + -y + ")";
});
// Draw the mesh
svg.append("g")
.selectAll("path")
.data(geo.features)
.enter()
.append("path")
.attr("fill", "none")
.attr("d", path)
//.attr("stroke", "rgba(50,50,50,0.2)")
// Add the labels
svg.append("g")
.selectAll("labels")
.data(geo.features)
.enter()
.append("text")
.attr("x", function(d){return path.centroid(d)[0]})
.attr("y", function(d){return path.centroid(d)[1]})
.text(function(d){ return d.properties.abbrv})
.attr("text-anchor", "middle")
.attr("alignment-baseline", "central")
.style("font-size", 11)
.style("fill", "rgba(25,25,25,0.6)")
.attr("transform","translate(0,-15)")
}
</script>
https://d3js.org/d3.v4.js
https://d3js.org/d3-scale-chromatic.v1.min.js
https://d3js.org/d3-geo-projection.v2.min.js