QGIS – How to Randomly Add Specified Number of Points Across Polygons in QGIS

pointqgisrandom

When I go to Vector > Research Tools > Random Points in Polygons in QGIS, I can specify a specific number of points I can add randomly into each feature (each polygon for me). So if I have 15 polygons, and I choose 1 point, I will find 1 point placed in each polygon in a random location.

However, I want to pre-specify a global number of points which are randomly added across all polygons. So for example, let's say I have 20 polygons and I specify 30 points to be randomly added across all of them (with an equal probability of appearing in each polygon). In this case, on average each polygon will end up with 1.5 points, but some may, by random chance, have 3, some may have 0 etc. Also, let's say I have 20 polygons and I specify 15 points. In this case, I will find out that by random chance at least 5 of my polygons end up with no points, and probably more than 5 because again, by random chance, probably a few polygons will end up with two or more points.

Is there a way to do this with QGIS?

Best Answer

You can use pyqgis.

This will list all features, select from the list n times and create a sample list, randomly place a point within each sample:

import random
layer = QgsProject.instance().mapLayersByName('ok_an_riks')[0]
sample_size = 50

features = [f for f in layer.getFeatures()] #List all features

#Sample
sampled = [] #A list to add randomly selected features to


for _ in range(0, sample_size): #For the number of sample size
    rand = random.randint(0, len(features)-1) #Pick one random integer between 0 and the number of features in the layer
    sampled.append(features[rand]) #Append this feature to the sampled list

#ids = sorted([f.id() for f in sampled])
#[2, 2, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9, 9, 10, 10, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 15, 16, 17, 18, 18, 18, 21, 21, 22, 23, 23, 23, 23, 25, 25, 25]
#So polygon 2 will get 2 points, 3 one point, ... 

def randpoint(feature):
    """Creates one randomly located point within an input polygon"""
    success = 0
    polygeom = feature.geometry() #Find the input features polygon geometry
    box = polygeom.boundingBox() #Find its bounding box
      
    while success != 1: #Do the following until ...
        xrand = random.uniform(box.xMinimum(), box.xMaximum()) #A random x coord within the bounding box
        yrand = random.uniform(box.yMinimum(), box.yMaximum()) #And y
        randompoint = QgsGeometry.fromPointXY(QgsPointXY(xrand, yrand)) #Create a point geometry
        if randompoint.within(polygeom): #Check if it is within the polygon (not only within the bounding box)
            success = 1 #... If within, stop iterating and move on to the next sampled feature
        
    return randompoint
    
#random_points = []

#Create the point layer
pointlayer = QgsVectorLayer("Point?crs={}&index=yes".format(layer.crs().authid()), "myLayer", "memory")
provider = pointlayer.dataProvider()
for sample in sampled:
    f = QgsFeature()
    f.setGeometry(randpoint(sample))
    provider.addFeature(f)

QgsProject.instance().addMapLayer(pointlayer)

print('Done')

enter image description here