Use Voronoi.find() to group data by the Voronoi cells of the top 10% data points.
See also the animated version.
Original work by Philippe Rivière for d3-voronoi (issue 17).
forked from Fil's block: Voronoi binning
xxxxxxxxxx
<meta charset="utf-8">
<style>
circle {
stroke: #444;
}
</style>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var color = d3.scaleOrdinal().range(d3.schemeCategory20);
var n = 400;
var data = d3.range(n)
.map(function(d,i) { return [Math.random() * width, Math.random() * height, color(i), Math.random()]; });
var voronoi = d3.voronoi()
.size([width, height]);
var measures = [];
for(var bins=10; bins< 100; bins++) {
var sites = data.sort(function(a,b) {
return d3.descending(a[3], b[3]);
})
.slice(0,bins);
var diagram = voronoi(sites);
diagram.find = find;
var totals = new Array(sites.length);
data.forEach(function(d){
var found = diagram.find(d[0],d[1]);
totals[found.index] = (totals[found.index] || 0) + d[3];
});
var mean = d3.mean(totals);
var stddev = Math.sqrt( totals
.map(function(d) { return (d-mean)*(d-mean);})
.reduce (function(sum, value){return sum+value})
/ totals.length);
measures.push([totals.length, mean, stddev]);
}
d3.select('svg')
.append('g')
.selectAll('circle')
.data(measures)
.enter()
.append('circle')
.attr('r', function(d) {return d[2];})
.attr('transform', function(d) { return 'translate('+ [ d[0]*6, d[2]*30 ] +')'; })
;
function find (x, y, radius){
// optimization: start from most recent result
var i, next = diagram.find.found || Math.floor(Math.random() * diagram.cells.length);
var cell = diagram.cells[next] || diagram.cells[next=0];
var dx = x - cell.site[0],
dy = y - cell.site[1],
dist = dx*dx + dy*dy;
do {
cell = diagram.cells[i=next];
next = null;
cell.halfedges.forEach(function(e) {
var edge = diagram.edges[e];
var ea = edge.left;
if (ea === cell.site || !ea) {
ea = edge.right;
}
if (ea){
var dx = x - ea[0],
dy = y - ea[1],
ndist = dx*dx + dy*dy;
if (ndist < dist){
dist = ndist;
next = ea.index;
return;
}
}
});
} while (next !== null);
diagram.find.found = i;
if (!radius || dist < radius * radius) return cell.site;
}
</script>
https://d3js.org/d3.v4.min.js