2

I have 2 point layers, say layer A and Layer B

Layer A with a bunch of points, Layer B with a single point.

I first need to measure all the distances between every single point in layer A and the point in layer B, Then draw a buffer of median distance, 20 percentile distance, 30 percentile distance etc.

How do I achieve this in bulk in QGIS?

The output will be like: enter image description here

2 Answers 2

2

You could create a Virtual Layer with the following query:

WITH distances AS(
  SELECT 
    b.fid b_fid,
    a.fid a_fid,
    ST_Distance(b.geometry,a.geometry) dist
  FROM layer_B b
  CROSS JOIN layer_A a
),
percentiles AS(
  SELECT
    b_fid,
    a_fid,
    dist,
    NTILE(10) OVER(
      PARTITION BY b_fid
      ORDER BY dist)*10 percentile
  FROM distances
),
radii AS(
  SELECT 
    b_fid,
    percentile,
    MAX(dist) radius
  FROM percentiles
  GROUP BY b_fid, percentile
)
--SELECT * FROM distances;
--SELECT * FROM percentiles;
--SELECT * FROM radii;
-- to debug, comment the following lines and uncomment the previous clause of interest
SELECT
  r.b_fid,
  r.percentile,
  r.radius,
  ST_Buffer(b.geometry,r.radius) geom
FROM layer_B b
INNER JOIN radii r
ON b.fid = r.b_fid
WHERE
  (r.percentile = 20
  OR r.percentile = 30
  OR r.percentile = 50);  

The previous query will work for one or more features in layer_B.

We are creating a table (distances) with all distances from all points in layer B to all points in layer A.

Then, we are creating a table (percentiles) with 10 groups of distances for each point in layer B.

Next, we are creatting the radii table selecting the maximum distance from each group of percentiles.

Finally, we are creating a buffer for each point in layer B and each radius of radii table, but filtering them to only those with percentiles 20, 30 and 50.


Notes:

  • I am assuming the layer_A and layer_B names of the source layers. Also, I am assuming fid and geometry field names (GeoPackage defaults). Replace that names in the query to match your layer and field names.

  • A virtual layer is stored in the project and is dinamically updated every time a source layer change. Export it to a file if features in source layers will not change.

3
  • Hi @Gabrial, by checking the doc here postgis.net/docs/ST_Distance.html, it seems that the crs needs to be WGS84 before running the function, since I am a bit confused by the double colons in the doc example , could you provide an example of how to transfer my geometries crs by using ST_Tranform?
    – Pete
    Commented Dec 15, 2019 at 10:07
  • @Pete, Hi. CRS doesn' t need to be WGS84. Absolutely. WGS84 is a geodetic system, its units are degrees, and degrees are not a unit of distance. If you need to make a transformation, I would recommend reprojecting the source layers. All you need to do is replace the names of the layers and fields and the query will work fine in any CRS. If you want to detail your names of layers and fields in the question I can modify them in the answer. Virtual layers are written in SpatiaLite. Always press the Test button before Add, to make sure that the virtual layer query does not return errors. Commented Dec 15, 2019 at 12:49
  • Hi @Gabriel, I have this question is because I first ran your code on Mac, the dist field turns out all blank and it shows no error while clicking test button, but it works perfectly when I run the same code on Windows. Not sure what's going on on Mac yet. Anyway, your solution is perfect for me, (on Windows though... lol)
    – Pete
    Commented Dec 16, 2019 at 12:22
0

Sure, run a Vector Analysis > Distance matrix between Layer A and Layer B, to output to a csv.

Run statistics on your distance matrix csv and buffer to your liking.

Your Answer

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

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