d3 / d3-voronoi Goto Github PK
View Code? Open in Web Editor NEWCompute the Voronoi diagram of a set of two-dimensional points.
License: Other
Compute the Voronoi diagram of a set of two-dimensional points.
License: Other
d3-voronoi v1.1.0
const v = d3.voronoi()([[0,0], [0,0]]);
v.find(0, 0); // <- Uncaught TypeError: Cannot read property 'site' of undefined(…)
If you inspect v.cells
you'll see that the first item in the array is undefined
instead of a cell object.
v.triangles()
also throws an exception, although a different message. And v.triangles()
returns an array where the first element is undefined
.
The documentation doesn't mention exceptions at all, which is why I didn't expect them.
diagram.find(x,y)
returns the closest site to point x,y
— in other words a cell that contains said point, except if we are out of the extent.
http://bl.ocks.org/Fil/1b7ddbcd71454d685d1259781968aefc
The algorithm is quite simple (I invented it, but probably someone already did before me!). It seems to converge in about sqrt(n) steps, involving a few distance computations each time.
The API is similar to d3-force simulation.find()
https://github.com/d3/d3-force/blob/master/src/simulation.js#L116
I encountered an issue that special input data can crash voronoi.polygons.
Reproduce Demo
var d3 = require("d3");
var width = 400;
var height = 400;
// change width and height to 100 works well
// var width = 100;
// var height = 100;
var x = d3.scaleLinear();
var y = d3.scaleLinear();
x.domain([0, 1]).range([0, width]).nice();
y.domain([0, 1]).range([height, 0]).nice();
var voronoi = d3.voronoi()
.extent([[-1, -1], [width + 1, height + 1]])
.x((pt) => x(pt.x))
.y((pt) => y(pt.y));
// TypeError: Cannot read property 'circle' of null
voronoi.polygons([
{x: 0.9999994485078688, y: 0},
{x: 0.9999994512180275, y: 0}
]);
I thought it was my scale range problem, but the following code works:
voronoi.polygons([
{x: 0.1, y: 0},
{x: 0.2, y: 0}
]);
Currently you have to recompute the entire Voronoi diagram to get these separately. It would be nice to compute all of them in one go.
Extending on top of #28 and #16, voronoi.polygons will either crash, return incorrect data, or run out of memory on certain sets of linear data.
JSFiddle demonstrating the second case (incorrect polygons) here: https://jsfiddle.net/y3t9026e/
I've also generated a couple of other bad datasets for all 3 different cases here: https://pastebin.com/hHxWEvb1
Unfortunately, Delaunay also fails for linear data sets (since triangles cannot be generated within points in a line), so that is not an option for the time being.
In addition to #1, we should think about voronoi.topology: d3/d3#1819.
I have a viz I want to make where I have a map segmented along district lines. I have points in each district and want to do a voronoi segmentation of that district along certain points. I would like to use the district polygon outline as extent, instead of a triangle.
The current definition obliterates the constructor
property.
Any plans (or wishes) to make this module use d3-delaunay internally, while exposing the same API? In that case, should this be done here, or should we on the contrary try and offer the old-style API in d3-delaunay?
Repro: http://jsbin.com/cucerakofa/edit?js,console
Ran into this with certain datasets (most work fine). I tried debugging and don't have a clue what's going on, but
in the clipCells
function, there's a chain of ternary operators ending with null
. It's precisely this null
(which is passed into createBorderEdge
as the final argument creating an edge with a null point on the end) which is later being accessed for property 0
and is causing the TypeError.
So I stumbled upon this bug with d3.voronoi with this particular dataset:
http://jsbin.com/sogamotefo/edit?html,js,console
The bug also exists in the most recent version of d3v3, and if you swap the accessors for x & y it actually causes the browser to hang indefinitely with no error messages as though it it stuck in a loop:
// warning, replacing voronoiGen in the jsbin with this snippet will cause the browser to hang.
var voronoiGen = d3.voronoi()
.x(function(d) {return y(d.y);})
.y(function(d) {return x(d.x);})
.extent([[0, 0], [500, 500]]);
The d3.voronoi module has the handy voronoi.find(x,y,r)
(#17 ) method, which returns the closest site to a given point, which is very useful for a number of applications. But what if we wanted all the sites within a given radius?
I've been working on a few things where a built in method would be handy, but also saw a question question on StackOverflow yesterday on the same topic that got me thinking, if we have a method to find the closest site, why not a method to find all sites within a given radius?
I've mocked up a potential method here, it takes the same parameters as voronoi.find
, but spits out an array of sites rather than a single one.
findAll: function(x, y, r) {
var diagram = this, center = diagram.find(x,y,r); // use the existing method to find central point
if(!center) return [];
var queue = [center], checked = []; // queue holds cells within the boundary
for(var i = 0; i < queue.length; i++) {
checked.push(queue[i].index); // don't check any cell twice
// find neighbors of current item:
var edges = diagram.cells[queue[i].index].halfedges;
var neighbors = edges.map(function(e) {
return (diagram.edges[e].left == queue[i]) ? diagram.edges[e].right : diagram.edges[e].left;
})
// for each neighbor, see if it is within the radius (and unchecked), if so, add to queue
neighbors.forEach(function(n) {
if(n && checked.indexOf(n.index) == -1) {
var dx = n[0] - x, dy = n[1] - y;
var d2 = dx*dx+dy*dy;
(d2>r*r) ? checked.push(n.index) : queue.push(n);
}
})
}
return queue;
}
And here's a demonstration.
Granted, this implementation leads to some cells potentially being examined more than once (first through the use of voronoi.find()
to get the initial cell); consequently, it could be re-worked to include a slightly modified voronoi.find() method to get started.
But, this might be getting ahead of myself. Is there value in including such a method in d3.voronoi?
I've been getting this error randomly when loading datasets into a plot. I've spent a few days now trying to find the root cause of this. I haven't been able to find any null values that I'm sending into the voronoi calculating code. So right now my chart is crashing routinely and I don't know what to do.
https://github.com/d3/d3-voronoi/blob/master/src/Cell.js#L16 uses Math.atan2
to give us the angle, but the result is only ever used to compare angles, so we could return the tangent instead.
Like some d3 layouts and functions. Voronoi seems to mutate data, but unlike some others (force for example adds properties but does not move them), all properties are dropped into a data node, and an array of 4 points is left at top level. As a result, it seems, I am unable to access the data properties to use a key function when joining when attempting to extend this example to apply animations with the general update pattern.
https://bl.ocks.org/mbostock/6526445e2b44303eebf21da3b6627320
Likewise, I am unable to to generate voronoi diagram without changing the data used elsewhere in my project. Which I think would be helpful as the voronoi is only being used in one state of my data display. Would it be preferable if it did not mutate, or am I missing something?
It seems the API as described here is now very different than the examples given, can we get some updated examples?
Hey, thanks for d3 and all its various great packages!
We (see beancount/fava#731) recently in an out of memory issue with one of the charts of Fava - a line chart (looking like this) using a voronoi diagram to provide tooltips. A call to voronoi.polygons() seemed to be the culprit and the following snippet on runkit seems to reproduce the error (it crashes with error code 137, which denotes 'out of memory' afaict): https://runkit.com/yagebu/5ac88e13ef4e310012a3c15f
I'm missing something, or there is a bug:
const points = [[100, 100], [200, 200], [300, 300]]
const voronoi = d3.voronoi()
.extent([0, 0], [400, 400])
const diagram = voronoi(points)
const polygons = diagram.polygons()
console.log(polygons)
gives
[
null,
null,
null
]
without the extent:
const points = [[100, 100], [200, 200], [300, 300]]
const voronoi = d3.voronoi()
const diagram = voronoi(points)
const polygons = diagram.polygons()
console.log(polygons)
gives
[
[
null
],
[
null,
null
],
[
null
]
]
😕
Hi!
I was wondering if, given the points used to make a line segments used to make up a closed shape, could you fine the voronoi point? if so what is the function that I would look at?
It’d be nice to be able to add a new point to an existing Voronoi diagram without having to start over from scratch. I’ve also been thinking about this divide-and-conquer algorithm as an alternative to Fortune’s:
http://www.personal.kent.edu/~rmuhamma/Compgeometry/MyCG/Voronoi/DivConqVor/divConqVor.htm
I'm using d3 4.2.2. I'm getting an exception in clipCells().
angular.js:13920 TypeError: Cannot read property '0' of null
at clipCells (d3.js:11482)
at new Diagram (d3.js:11849)
at voronoi (d3.js:11918)
at Function.voronoi.polygons (d3.js:11927)
...
Looking at the code it appears that the variable end is referenced end[0] before it is populated with a value.
https://github.com/d3/d3-voronoi/blob/master/src/Cell.js#L75
I don't have a simple test case right now since I'm seeing this exception buried under several other layers of 3rd party code that ends up calling d3.
Thanks for having a look.
Discovered this while using triangles() to generate a mesh for interpolating some points. Noticed that some of my points were not inside any triangles. I was surprised to find that a triangle was missing from the mesh. Pruned my data down to 4 vertices, which should yield 2 triangles, but yields just 1. I've tried tweaking the vertices slightly, which results in the expect number of triangles.
v = require("d3-voronoi").voronoi();
vertices = [[47.307,105.33],[51.707,104.13],[52.717,110.74],[53.917,106.34]];
console.log(v.triangles(vertices)); // returns 1 triangle
vertices[3][1] += 0.001 // tweak one of the values slightly
console.log(v.triangles(vertices)); // returns 2 triangles (as expected)
Related d3/d3#2401. For example: Manhattan, Chebychev, and Minovsky.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.