3

The Voronoi polygon algorithm propagates the polygons to the extent of the input layer (the points), which means some massive polygons. The majority of those massive polygons are nonsense data - we can't have any confidence that the values there are reasonable just because the value at a point a long way away is X (and that happens to be the nearest point sampled).

Potential solutions:

  1. set a single universal maximum distance from node point, so the polygons would be rounded out instead of continue.
  2. set a dynamic maximum distance based on nearby points... but I suspect that'd get complicated quick.

I'm not sure how to do this though. The Voronois are created by an algorithm in QGis, using the points as input. But the resulting voronoi polygons layer doesn't know where the points are. There doesn't look to be an option for this in the algorithm (Python function), sadly.

Possibly I could attach the input points to the output Voronoi somehow, to act as centroids for step 2. Step 2: apply some kind of buffering algorithm to each polygon, i.e. "set extent to be the current bounds or a circle of Y radius, whichever's smallest.

Has anyone ever done this?

Voronois being untrustable at a certain projection distance seems like something others would have had to deal with.

This picture shows points around Florida, USA. Easy to remove the centre by masking land, but I need ocean points to append to a grid and lots of them are going to be unreasonable/wrong.

Voronoi

2 Answers 2

4

Another solution using concave hull: first "cluster" nearby points into different groups, then create Voronoi polygons for each clustered group separately:

  1. Create a concave hull (alpha shapes) around your points: use a small Threshold value to get a small hull:

Create concave hull (blue) around the points with Threshold = 0.1: enter image description here

  1. On the resulting layer, run multipart to single parts.

  2. Attach the id of the features of the output of step 2 (the individual polygons of the concave hull) to the points: so each point gets an attribute as to whicht "cluster" it belongs. Create a new field called cluster_group on the point layer with field calculator and this expression: array_first (overlay_within ('clusters',$id))

enter image description here

  1. Now select each group individually using select by expression with an expression like cluster_group = 1 etc. and create Voronoi polygons separately for each group: enter image description here

  2. Clip the resulting voronoi polygon layer (yellow) with the clusters layer from step 2 (blue):

enter image description here

See result: enter image description here

And this is how the result for the wholy layer looks like:

enter image description here

2
  • This is great, thank you, and sorry for the slow reply. I presume it should be decently possible to buffer the concave hulls (after step 1) right? Otherwise there'll be edge & corner points with no extrapolation area outside of the concave hull. I'll have a look tomorrow regardless. Cheers!
    – dez93_2000
    Oct 26, 2021 at 5:17
  • Yes, you're right. Of course, a reasonable buffering would probably be a good idea if you want to include some area outside.
    – Babel
    Oct 26, 2021 at 11:42
3

Quick solution / principles

See below for variation with dynamic distance buffer

  1. Create voronoi polygons from your points (as you already did).
  2. Create a buffer around your points and be sure to check the dissolve option.
  3. Intersect buffer with polygon layer.

Voronoi polygons (blue) of the white points; red: dissolved buffer around the points: enter image description here

Green: voronoi polygons intersected with the buffers - everything outside of the buffer layer is clipped from the voronoi layer: enter image description here

Variations

  1. Make buffer with a dynamic distance, based on the density of the points (based on the nearest neighboring point). In the buffer tool, for Distance use data driven override and insert this expression (you can modify it to vary the buffer size even further):
length (
    make_line (
        $geometry, 
        array_first (
            overlay_nearest (
                'points',
                $geometry
))))

enter image description here

  1. On the buffer layer, run Multipart to single parts before intersection.

  2. After intersection, on the output layer check if there are any polygons that do not contain points (this is the case where the buffer of a points partially falls inside the voronoi polygon of another point - see screenshot). To select these "empty" poylgons, use Select by expression with this expression, where points is the name of the layer containing the points: overlay_contains( 'points') = false. Delete the selected polygons.

"Empty" polygons, highlighted in yellow; red: buffer with dynamic size, black lines: boundary of the voronoi polygons: enter image description here

Green: resulting voronoi polygons, clipped with a buffer with dynamic distance: enter image description here

Result, showing the whole result: voronoi-polygons clipped to a dynamic distance around the points, based on the density of the points (the closer points are, the smaller the voronoi polygons). Of course, there are no overlaps between polygons, but sometimes gaps between them: enter image description here

4
  • Fabulous stuff, thanks again! I suspect static distance is most defensible. I'll have to think of a way to decide that value. I wonder if I could do some kind of nearest neighbour analysis... see if there's a falling trend in autocorrelation to the same value as distance to NN increases?
    – dez93_2000
    Oct 26, 2021 at 5:23
  • What do you mean by nearest neigbour analysis? The distance based on the N nearest neighbours? That is possible modifying the overlay_nearest function with a limit:=N argument to get the N nearest neighbours and then calculate let's say the mean distance.
    – Babel
    Oct 26, 2021 at 11:40
  • I'm not using the right terms I suspect. I'm thinking: Find each point's single nearest neighbour, extract the value of that point, compare it to the value of the 'source node', and do that for every node. Resulting columns would be 'dist to nearest neighbour' and 'modulus of value difference'. Plot that, x=dist, y=mod, draw trendline. Sounds like overlay_nearest limit:=1 would be a start. Cheers!
    – dez93_2000
    Oct 26, 2021 at 16:40
  • Sorted. Went for an eyeballed static rate. Thank you so much for your wonderful walkthrough!
    – dez93_2000
    Nov 3, 2021 at 21:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.