A graduated size and color hexbin that displays the total value of diamonds of a particular carat and depth from a dataset of 50k+ such diamonds. The style follows that of Scatterplot Matrix Techniques for Large N. Graduated hexbins that aggregate value do a better job of showing spatial distribution of values, as contrasted with graduated symbols that occlude each other as well as the region their purport to represent.
Here's a version that shows the raw number of items in each hex using the same color and symbology.
xxxxxxxxxx
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Aggregate Value Graduated Size and Color Hexbin</title>
<style>
svg {
background: #3b7e77;
}
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
fill: none;
stroke: #000;
stroke-width: 1.5px;
opacity: 0.4;
marker-end: url(#end-arrow);
}
.domain {
fill: none;
stroke: #5ba8b8;
}
.tick > line {
stroke: #5ba8b8;
}
.tick > text {
fill: #5ba8b8;
}
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.min.js" charset="utf-8" type="text/javascript"></script>
<script src="d3.hexbin.js" charset="utf-8" type="text/javascript"></script>
<script>
var xAtt = "carat";
var yAtt = "depth";
var hexsize = 5;
bgColors = d3.scale.threshold().domain([1,1000,100000,1000000,5000000]).range(["none","none","#0481ad","#39957c","#c18779"]);
fgColors = d3.scale.threshold().domain([1,1000,100000,1000000,5000000]).range(["none","#1d3b3d","#035c94","#386b5c","#363b37"]);
priceSizeScale = d3.scale.linear().domain([1,1000,1001,100000,100001,1000000,1000001,5000000]).range([0,hexsize,0,hexsize,0,hexsize,0,hexsize]);
//These attributes could be derived from the data
attributes = ["carat","depth","table","price","x","y","z"];
d3.csv("https://gist.githubusercontent.com/emeeks/613cd391ba7e9a3a4042/raw/5c3711f9e3f55bea40ce21f765dc373a28cf72de/diamonds.csv", hexbin);
d3.select("body").append("svg").attr("height", 850).attr("width", 800)
function hexbin(data) {
//d3.csv pulls in data as strings so they need to be formatted as numbers
data.forEach(function (d) {
attributes.forEach(function (att) {
d[att] = parseFloat(d[att])
})
})
xExtent = d3.extent(data, function (d) {return d[xAtt]});
xScale = d3.scale.linear();
xScale.domain(xExtent).range([20,995]);
yExtent = d3.extent(data, function (d) {return d[yAtt]});
console.log(yExtent)
yScale = d3.scale.linear();
yScale.domain(yExtent).range([995,20]);
var hexbin = d3.hexbin()
.size([1000,1000])
.x(function (d) {return xScale(d[xAtt])})
.y(function (d) {return yScale(d[yAtt])})
.radius(hexsize);
//bind the matrix array to a grid of g elements
d3.select("svg")
.append("g")
.attr("class", "hexbin")
.attr("transform", function (d) {return "translate(30,-200)" });
d3.select("g")
.selectAll("path.bg")
.data(hexbin(data))
.enter()
.append("path")
.style("fill", function (d) {return bgColors(d3.sum(d, function (d) {return d.price}))})
.style("stroke", function (d) {return bgColors(d3.sum(d, function (d) {return d.price}))})
.attr("d", function(d) { return hexbin.hexagon(hexsize); })
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
d3.select("g")
.selectAll("path.fg")
.data(hexbin(data))
.enter()
.append("path")
.style("fill", function (d) {return fgColors(d3.sum(d, function (d) {return d.price}))})
.style("stroke", function (d) {return fgColors(d3.sum(d, function (d) {return d.price}))})
.attr("d", lastNumber)
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10)
.tickSize(0)
.tickSubdivide(true);
xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(10)
.tickSize(0)
.tickSubdivide(true);
d3.select("g.hexbin").append("g").call(yAxis)
d3.select("g.hexbin").append("g").attr("transform", "translate(0,1000)").call(xAxis)
function lastNumber(d) {
var sl = d3.sum(d, function (d) {return d.price});
return hexbin.hexagon(priceSizeScale(sl));
}
}
</script>
</body>
</html>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.min.js