block by fil 7c3c41f1524dcf2caea54290cceddf0a

Voronoi binning

Full Screen

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).

index.html

<!DOCTYPE html>
<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 = 4000;
  
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 sites = data.sort(function(a,b) {
  return d3.descending(a[3], b[3]);
})
.slice(0,n/10); 

var diagram = voronoi(sites);
diagram.find = find;


d3.select('svg')
.append('g')
.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('r', function(d) {return 10 * d[3] * d[3];})
.attr('transform', function(d) { return 'translate('+ [ d[0], d[1] ] +')'; })
.attr('fill', function(d) {
  var found = diagram.find(d[0],d[1]);
  return sites[found.index][2];
});


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>