Built with blockbuilder.org
References: https://observablehq.com/@larsvers/making-a-tesselated-hexbin-map https://bl.ocks.org/veltman/38149d05ea247cbcebb1/a7e57c31b82bfaf7c46587635e8c119da5e45008 https://bl.ocks.org/mbostock/9885854/8967c821e056e2f8ed3a1432e7b43fa8293078b0 https://bl.ocks.org/veltman/c582a31d347e04dd75d5331b0074558e/123ef658b4db1eee28c662e7a5ee4d4d3258ba95
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="d3.v5.min.js"></script>
<script src="topojson.v2.min.js"></script>
<script src="d3-hexbin.v0.2.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
svg { width: 100%; height: 90%;}
.landshadow {
fill: none;
stroke: #ccc;
stroke-width: 2px;
stroke-linejoin: round;
}
.states {
fill: none;
stroke: #fff;
stroke-linejoin: round;
}
.counties {
fill: #ffffff;
}
svg.circle {
opacity: 0.2;
}
</style>
</head>
<body>
<script>
var svg = d3.select("body").append("svg");
var projection = d3.geoAlbersUsa().translate([400,250]).scale(800);
var path = d3.geoPath().projection(projection);
var url = "https://enjalot.github.io/wwsd/data/world/world-110m.geojson";
var data_url = "https://enjalot.github.io/wwsd/data/world/ne_50m_populated_places_simple.geojson";
var us_counties_shapes_url = "us.json";
var pvs_counties_data_url = "pvscounty_fips.tsv";
var pvs_points_url = "pvscoords.csv";
var hexbin = d3.hexbin()
.extent([[0, 0], [svg.width, svg.height]])
.radius(10);
hexbin.x(d => {
return projection([+d.lon,+d.lat]) ? projection([+d.lon,+d.lat])[0] : null;
});
hexbin.y(d => {
return projection([+d.lon,+d.lat]) ? projection([+d.lon,+d.lat])[1] : null;
});
function cmyk(d) {
if (d.PCTPOP == 0 && d.PCTSODA == 0 && d.PCTCOKE == 0 && d.PCTOTHER == 0) {
return "white";
} else {
return "rgb("
+ Math.round((d.PCTPOP + d.PCTCOKE) * 100) + "%,"
+ Math.round((d.PCTSODA + d.PCTPOP) * 100) + "%,"
+ Math.round((d.PCTCOKE + d.PCTSODA) * 100) + "%)";
}
}
Promise.all([d3.json(us_counties_shapes_url),d3.tsv(pvs_counties_data_url),d3.csv(pvs_points_url)]).then(function(data) {
var us = data[0];
var pvscounty_fips = data[1];
var points = data[2];
var pvscounty_lookup = {};
pvscounty_fips.forEach(function(d) {
pvscounty_lookup[d.id] = {
PCTPOP: +d.PCTPOP,
PCTSODA: +d.PCTSODA,
PCTCOKE: +d.PCTCOKE,
PCTOTHER: +d.PCTOTHER,
SUMPOP: +d.SUMPOP,
SUMSODA: +d.SUMSODA,
SUMCOKE: +d.SUMCOKE,
SUMOTHER: +d.SUMOTHER,
}
});
svg.append("path").datum(topojson.feature(us, us.objects.land))
.attr("class", "landshadow")
.attr("d", path);
var counties = svg.append("g")
.attr("class", "counties")
.selectAll("path")
.data(topojson.feature(us, us.objects.counties).features)
.enter().append("path")
.attr("d", path);
/*
counties
.style("fill", function(d) {
//var threshold = 0.6;
var result = pvscounty_lookup[d.id];
if (result) {
//if (result.PCTPOP > threshold || result.PCTSODA > threshold || result.PCTCOKE > threshold)
return cmyk(result);
} else {
console.log("county id not found:", d.id);
//return 'red';
}
});
*/
points.forEach(d => {
d.SUMPOP = +d.pop;
d.SUMSODA = +d.soda;
d.SUMCOKE = +d.coke;
d.SUMOTHER = +d.other;
d.PCTPOP = d.SUMPOP/+d.count;
d.PCTSODA = d.SUMSODA/+d.count;
d.PCTCOKE = d.SUMCOKE/+d.count;
d.PCTOTHER = d.SUMOTHER/+d.count;
d.lat = +d.lat;
d.lon = +d.lon;
d.count = +d.count;
});
/*
svg.append("g").selectAll("circle")
.data(points
.filter(d => projection([+d.lon,+d.lat])) // filter anything where proj fails
.filter(d => d.zip != 92122 && d.zip != 77069 && d.zip != 82401) // filter some bad data
)
.enter()
.append("circle")
.attr("r", function(d) {
return d.count / 10;
})
.attr("fill", function(d) {
return cmyk(d);
})
.attr("cx", function(d) {
return projection([+d.lon,+d.lat])[0];
})
.attr("cy", function(d) {
return projection([+d.lon,+d.lat])[1];
})
//.on("mouseover", d => {
// console.log(d.zip);
//});
*/
svg.append("g")
.attr("class", "hexbins")
.attr("clip-path", "url(#us-clip)") // clip to the shape of the us
.selectAll("path")
.data(hexbin(points))
.enter().append("path")
.attr("class", "hexagon")
.attr("d", function(d) { return hexbin.hexagon(); })
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.attr("fill", function(d) {
var arrayvalues = Array.from(d);
d.PCTPOP = d3.sum(arrayvalues, i => i.SUMPOP)/d3.sum(arrayvalues, i => i.count);
d.PCTSODA = d3.sum(arrayvalues, i => i.SUMSODA)/d3.sum(arrayvalues, i => i.count);
d.PCTCOKE = d3.sum(arrayvalues, i => i.SUMCOKE)/d3.sum(arrayvalues, i => i.count);
d.PCTOTHER = d3.sum(arrayvalues, i => i.SUMOTHER)/d3.sum(arrayvalues, i => i.count);
return cmyk(d);
});
//var topology = topojson.topology();
// Add the us outline again just for clipping
svg.append("clipPath").datum(topojson.feature(us, us.objects.land))
.attr("id", "us-clip")
.append("path")
.attr("d", path);
// Add the shapes of states on top, to have outlines.
svg.append("path").datum(topojson.mesh(us, us.objects.states, function(a, b) {
return a.id !== b.id;
})).attr("class", "states").attr("d", path);
});
</script>
</body>