Here is a PyQGIS solution (in the form of a custom processing script) which should do what you are asking.
This script algorithm has two optional input parameters. The first is a QgsProcessingParameterVectorLayer
, the second a QgsProcessingParameterExtent
. Therefore the input can either be a polygon vector layer, or an extent (layer, canvas, or draw on canvas). If both inputs are filled, the layer will be used and the extent ignored, if neither are filled, a helpful error dialog will be shown.
If a layer input is used, a processing.run()
call is made to "native:randompointsinpolygons"
as a child algorithm.
if an extent is used, the call is made to "native:randompointsinextent"
as a child algorithm.
In this way your requirement is satisfied, that the user can select either an input layer or file, or draw a rectangle extent on the canvas, and the script will handle and process the input accordingly.
If you save this script as a .py
file, you can add it to the Processing Toolbox by clicking the Python icon on the toolbar at the top of the Processing Toolbox dock widget, and selecting 'Add Script to Toolbox...'. You can then find and run the algorithm under Scripts -> Examples.

The dialog for the algorithm will look like this:

The full processing script is shown below:
"""
Name : Random_points_from_input
Group : Examples
INSTRUCTIONS: Save this script as .py file. Open the QGIS Processing Toolbox,
click the 'Scripts' tool button and select 'Add Script to Toolbox', navigate to
where you saved this script and click 'Open'. You can then double click the script
in the toolbox to run this model like any other processing algorithm.
"""
from qgis.PyQt.QtCore import QVariant
from qgis.core import QgsProcessing
from qgis.core import QgsProcessingAlgorithm
from qgis.core import QgsProcessingFeedback
from qgis.core import QgsProcessingParameterExtent
from qgis.core import QgsProcessingParameterVectorLayer
from qgis.core import QgsProcessingParameterVectorDestination
from qgis.core import QgsProject
import processing
class Random_points_from_input(QgsProcessingAlgorithm):
INPUT = 'INPUT'
EXTENT = 'EXTENT'
OUTPUT = 'OUTPUT'
def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT, 'Input Polygon Layer', types=[QgsProcessing.TypeVectorPolygon], defaultValue=None, optional=True))
self.addParameter(QgsProcessingParameterExtent(self.EXTENT, 'Extent (Will be ignored if input polygon layer is supplied)',
defaultValue=None,
optional=True))
self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUT, 'Random Points', type=QgsProcessing.TypeVectorPoint, createByDefault=True, defaultValue=None))
def processAlgorithm(self, parameters, context, feedback):
results = {}
outputs = {}
poly_source = self.parameterAsVectorLayer(parameters, self.INPUT, context)
extent_source = self.parameterAsExtent(parameters, self.EXTENT, context)
if poly_source is not None:
alg_params = {'INPUT': poly_source,
'POINTS_NUMBER': 25,
'MIN_DISTANCE': 0,
'MIN_DISTANCE_GLOBAL': 0,
'MAX_TRIES_PER_POINT': 10,
'SEED': None,
'INCLUDE_POLYGON_ATTRIBUTES': True,
'OUTPUT': parameters[self.OUTPUT]}
outputs['RandomPointsInPolygons'] = processing.run("native:randompointsinpolygons", alg_params, context=context, feedback=feedback, is_child_algorithm=True)
results['RandomPoints'] = outputs['RandomPointsInPolygons']['OUTPUT']
return results
if extent_source is not None:
# Random points in extent
alg_params = {
'EXTENT': extent_source,
'MAX_ATTEMPTS': 200,
'MIN_DISTANCE': 0,
'POINTS_NUMBER': 25,
'TARGET_CRS': context.project().crs(),
'OUTPUT': parameters[self.OUTPUT]
}
outputs['RandomPointsInExtent'] = processing.run('native:randompointsinextent', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
results['RandomPoints'] = outputs['RandomPointsInExtent']['OUTPUT']
return results
return {}
def name(self):
return 'Random_points_from_input'
def displayName(self):
return 'Random_points_from_input'
def group(self):
return 'Examples'
def groupId(self):
return 'Examples'
def checkParameterValues(self, parameters, context):
if parameters[self.INPUT] is None and parameters[self.EXTENT] is None:
return (False, 'Missing parameter value for input Layer or Extent')
return (True, '')
def createInstance(self):
return Random_points_from_input()
QgsProcessingParameterExtent