7

I have a shapefile of points representing households in a household survey.

In order to conceal their exact geographic location, I would like to displace these points in a random distance (uniform distribution over 0-2km) and a random direction (uniform distribution over 0-360 degrees).

How can I do this in QGIS?

Edit: Solution informed by replies:

Although displacing on the x and y axis independently creates a random direction, displacing by 2000m on the x and 2000m on the y would lead to more than a 2000m displacement in total. I thought about displacing up to 1414.2135m on both axes, but I wasn't convinced this would generate a uniform distribution over distance (I could be wrong, but I thought it would more likely create smaller distances).

The workaround I came up with was to create a random degree using the field editor rand(0,90) and a random quadrant using rand(1,4). Then I created a random distance using rand(0,2000). Let x* be the displaced x-coordinate of original point; similarly, y* is the displaced y-coordinate of the original point.

In quadrant I, x*=x+distancesin(degree) and y=y+distance*sin(90-degree)

In quadrant II, x*=x-distancesin(90-degree) and y=y+distance*sin(degree)

In quadrant III, x*=x-distancesin(degree) and y=y-distance*sin(90-degree)

In quadrant IV, x*=x+distancesin(90-degree) and y=y-distance*sin(degree)

  • 1
    Another solution would be to create a 2 km buffer around the points, and use the random points in polygon tool to generate one random point per buffer polygon. Much simpler than calculating random angles. – csk Oct 24 '19 at 15:21
2

I had never done this before but I think I that you can give my solution a try. What I did was to add two new X and Y fields to my shapefile (my layer projected in UTM18N, which is meters). Then, I used the field calculator to obtain the UTM coordinates of each point but adding to it a random value between 100 and 200. I input $x+(rand(100,200)) and $y+(rand(100,200)).

You export this layer as CSV and then reload it to QGIS as a delimited text file using these new X and Y fields. Your points will be randomly displaced. I tried it out in QGIS and it works; see the image below.

Edit: you can try some thing like $y+(rand(rand(-200,-100),rand(100,200))) if you want more dispersion. I still haven't figure out how to do the 0-360 degrees part.

I hope it helps.

enter image description here

|improve this answer|||||
  • Thank you for your comment. Please see my edit to the original post to see if my proposed solution for degree makes sense – rachel Oct 24 '19 at 15:18
  • Instead of using the field calculator to calculate new coordinates as attributes, then exporting and re-importing, try using the geometry by expression tool to generate new geometries in one step. Make a point out of your randomly displaced X and Y coordinates like this: make_point($x+(rand(-2000,2000)), $y+(rand(-2000,2000)). Using -2000 and 2000 as the offset, in a CRS that uses meters, will give you a displacement of up to 2 km in any direction. – csk Oct 24 '19 at 15:18
2

Use "Geometry generator"

Actually, QGIS provides a much easier way to do this: Geometry generator.

No need to create any new layer, nor any new calculated field, just add a Geometry generator marker in the Symbology pane, with soemthing similar to this content:

make_point(
  $x + rand(-2000,2000),
  $y + rand(-2000,2000)
  )

or, to get a true 2km radius:

with_variable('randang', rand(0,360),
with_variable('randdist', rand(0,2000),
make_point(
  $x+@randdist*cos(@randang),
  $y+@randdist*sin(@randang)
  )
  ))

enter image description here

  • yellow dots are the original, actual points
  • red dots are the randomized ones.

You can of course remove the representation of the actual points, and leave only the randomized one, which addresses your question:

enter image description here

Checking the correctness

You can also check the correctness of this approach by drawing displacement lines instead of displaced points:

enter image description here

This is accomplished selecting LineString / MultiLineString as Geometry type and with the following:

with_variable('randang', rand(0,360),
with_variable('randdist', rand(0,2000),
make_line(
    make_point($x+@randdist*cos(@randang),$y+@randdist*sin(@randang)),
    make_point($x,$y)
  )
))
|improve this answer|||||
2

Alternatively, I can suggest using a "Virtual Layer" through Layer > Add Layer > Add/Edit Virtual Layer...

Tested on QGIS 2.18 and QGIS 3.4

Let's assume there is a polyline layer called "points".

input

With the following Query, it is possible to achieve the result where each point will be shifted on a certain delta generated randomly.

SELECT points.id, points.name,
       make_point(st_x(geometry)+random() % 100,st_y(geometry)+random() % 100),
       random() % 100 AS delta_x, random() % 100 AS delta_y
FROM points

The output Virtual Layer with its corresponding attribute table will look as following

output


References:

|improve this answer|||||
1

The answer by @1buzz seems complete to me in terms of achieving movement in both random distance and random direction (rotation if you will). Since the x and y random displacements are independent of each other, then this accomplishes a shift in a random direction as well as a random distance from the source point, within the constraints imposed. However, you need to cater for negative displacements as well as positives, so what about $x = $x+randf(-2000,2000) and same for y, which should open up the randomized space to a square centred on the original point (as I understand it, randf returns a floating number rather than an integer). You might decide the integer returned by "rand" is sufficient.

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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