mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
Port random selection algorithms to new API
And heavily optimise random selection within subsets alg
This commit is contained in:
parent
a64d199e6f
commit
7ab82444f1
@ -99,6 +99,8 @@ from .RandomPointsAlongLines import RandomPointsAlongLines
|
||||
from .RandomPointsExtent import RandomPointsExtent
|
||||
from .RandomPointsLayer import RandomPointsLayer
|
||||
from .RandomPointsPolygons import RandomPointsPolygons
|
||||
from .RandomSelection import RandomSelection
|
||||
from .RandomSelectionWithinSubsets import RandomSelectionWithinSubsets
|
||||
from .RasterLayerStatistics import RasterLayerStatistics
|
||||
from .RegularPoints import RegularPoints
|
||||
from .ReverseLineDirection import ReverseLineDirection
|
||||
@ -135,8 +137,6 @@ from .VoronoiPolygons import VoronoiPolygons
|
||||
from .ZonalStatistics import ZonalStatistics
|
||||
|
||||
# from .ExtractByLocation import ExtractByLocation
|
||||
# from .RandomSelection import RandomSelection
|
||||
# from .RandomSelectionWithinSubsets import RandomSelectionWithinSubsets
|
||||
# from .SelectByLocation import SelectByLocation
|
||||
# from .SpatialJoin import SpatialJoin
|
||||
# from .GridLine import GridLine
|
||||
@ -185,7 +185,6 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
|
||||
|
||||
def getAlgs(self):
|
||||
# algs = [
|
||||
# RandomSelection(), RandomSelectionWithinSubsets(),
|
||||
# SelectByLocation(),
|
||||
# ExtractByLocation(),
|
||||
# SpatialJoin(),
|
||||
@ -270,6 +269,8 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
|
||||
RandomPointsExtent(),
|
||||
RandomPointsLayer(),
|
||||
RandomPointsPolygons(),
|
||||
RandomSelection(),
|
||||
RandomSelectionWithinSubsets(),
|
||||
RasterLayerStatistics(),
|
||||
RegularPoints(),
|
||||
ReverseLineDirection(),
|
||||
|
@ -30,13 +30,16 @@ import os
|
||||
import random
|
||||
|
||||
from qgis.PyQt.QtGui import QIcon
|
||||
from qgis.core import QgsFeatureSink, QgsProcessingUtils
|
||||
from qgis.core import (QgsFeatureSink,
|
||||
QgsProcessingException,
|
||||
QgsProcessingUtils,
|
||||
QgsProcessingParameterVectorLayer,
|
||||
QgsProcessingParameterEnum,
|
||||
QgsProcessingParameterNumber,
|
||||
QgsProcessingParameterFeatureSink,
|
||||
QgsProcessingOutputVectorLayer)
|
||||
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
|
||||
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
|
||||
from processing.core.parameters import ParameterSelection
|
||||
from processing.core.parameters import ParameterVector
|
||||
from processing.core.parameters import ParameterNumber
|
||||
from processing.core.outputs import OutputVector
|
||||
|
||||
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
|
||||
|
||||
@ -61,13 +64,14 @@ class RandomSelection(QgisAlgorithm):
|
||||
self.methods = [self.tr('Number of selected features'),
|
||||
self.tr('Percentage of selected features')]
|
||||
|
||||
self.addParameter(ParameterVector(self.INPUT,
|
||||
self.tr('Input layer')))
|
||||
self.addParameter(ParameterSelection(self.METHOD,
|
||||
self.tr('Method'), self.methods, 0))
|
||||
self.addParameter(ParameterNumber(self.NUMBER,
|
||||
self.tr('Number/percentage of selected features'), 0, None, 10))
|
||||
self.addOutput(OutputVector(self.OUTPUT, self.tr('Selection'), True))
|
||||
self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
|
||||
self.tr('Input layer')))
|
||||
self.addParameter(QgsProcessingParameterEnum(self.METHOD,
|
||||
self.tr('Method'), self.methods, False, 0))
|
||||
self.addParameter(QgsProcessingParameterNumber(self.NUMBER,
|
||||
self.tr('Number/percentage of selected features'), QgsProcessingParameterNumber.Integer,
|
||||
10, False, 0.0, 999999999999.0))
|
||||
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (random)')))
|
||||
|
||||
def name(self):
|
||||
return 'randomselection'
|
||||
@ -76,23 +80,20 @@ class RandomSelection(QgisAlgorithm):
|
||||
return self.tr('Random selection')
|
||||
|
||||
def processAlgorithm(self, parameters, context, feedback):
|
||||
filename = self.getParameterValue(self.INPUT)
|
||||
layer = QgsProcessingUtils.mapLayerFromString(filename, context)
|
||||
method = self.getParameterValue(self.METHOD)
|
||||
layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
|
||||
method = self.parameterAsEnum(parameters, self.METHOD, context)
|
||||
|
||||
featureCount = layer.featureCount()
|
||||
value = int(self.getParameterValue(self.NUMBER))
|
||||
|
||||
layer.removeSelection()
|
||||
value = self.parameterAsInt(parameters, self.NUMBER, context)
|
||||
|
||||
if method == 0:
|
||||
if value > featureCount:
|
||||
raise GeoAlgorithmExecutionException(
|
||||
raise QgsProcessingException(
|
||||
self.tr('Selected number is greater than feature count. '
|
||||
'Choose a lower value and try again.'))
|
||||
else:
|
||||
if value > 100:
|
||||
raise GeoAlgorithmExecutionException(
|
||||
raise QgsProcessingException(
|
||||
self.tr("Percentage can't be greater than 100. Set a "
|
||||
"different value and try again."))
|
||||
value = int(round(value / 100.0, 4) * featureCount)
|
||||
@ -100,4 +101,4 @@ class RandomSelection(QgisAlgorithm):
|
||||
selran = random.sample(list(range(featureCount)), value)
|
||||
|
||||
layer.selectByIds(selran)
|
||||
self.setOutputValue(self.OUTPUT, filename)
|
||||
return {self.OUTPUT: parameters[self.INPUT]}
|
||||
|
@ -31,15 +31,17 @@ import random
|
||||
|
||||
from qgis.PyQt.QtGui import QIcon
|
||||
|
||||
from qgis.core import QgsFeature, QgsFeatureSink, QgsProcessingUtils
|
||||
|
||||
from qgis.core import (QgsFeatureRequest,
|
||||
QgsProcessingException,
|
||||
QgsProcessingUtils,
|
||||
QgsProcessingParameterVectorLayer,
|
||||
QgsProcessingParameterEnum,
|
||||
QgsProcessingParameterField,
|
||||
QgsProcessingParameterNumber,
|
||||
QgsProcessingParameterFeatureSink,
|
||||
QgsProcessingOutputVectorLayer)
|
||||
from collections import defaultdict
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
|
||||
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
|
||||
from processing.core.parameters import ParameterSelection
|
||||
from processing.core.parameters import ParameterVector
|
||||
from processing.core.parameters import ParameterNumber
|
||||
from processing.core.parameters import ParameterTableField
|
||||
from processing.core.outputs import OutputVector
|
||||
|
||||
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
|
||||
|
||||
@ -65,16 +67,17 @@ class RandomSelectionWithinSubsets(QgisAlgorithm):
|
||||
self.methods = [self.tr('Number of selected features'),
|
||||
self.tr('Percentage of selected features')]
|
||||
|
||||
self.addParameter(ParameterVector(self.INPUT,
|
||||
self.tr('Input layer')))
|
||||
self.addParameter(ParameterTableField(self.FIELD,
|
||||
self.tr('ID Field'), self.INPUT))
|
||||
self.addParameter(ParameterSelection(self.METHOD,
|
||||
self.tr('Method'), self.methods, 0))
|
||||
self.addParameter(ParameterNumber(self.NUMBER,
|
||||
self.tr('Number/percentage of selected features'), 1, None, 10))
|
||||
|
||||
self.addOutput(OutputVector(self.OUTPUT, self.tr('Selection stratified'), True))
|
||||
self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
|
||||
self.tr('Input layer')))
|
||||
self.addParameter(QgsProcessingParameterField(self.FIELD,
|
||||
self.tr('ID field'), None, self.INPUT))
|
||||
self.addParameter(QgsProcessingParameterEnum(self.METHOD,
|
||||
self.tr('Method'), self.methods, False, 0))
|
||||
self.addParameter(QgsProcessingParameterNumber(self.NUMBER,
|
||||
self.tr('Number/percentage of selected features'),
|
||||
QgsProcessingParameterNumber.Integer,
|
||||
10, False, 0.0, 999999999999.0))
|
||||
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (stratified random)')))
|
||||
|
||||
def name(self):
|
||||
return 'randomselectionwithinsubsets'
|
||||
@ -83,61 +86,52 @@ class RandomSelectionWithinSubsets(QgisAlgorithm):
|
||||
return self.tr('Random selection within subsets')
|
||||
|
||||
def processAlgorithm(self, parameters, context, feedback):
|
||||
filename = self.getParameterValue(self.INPUT)
|
||||
layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
|
||||
method = self.parameterAsEnum(parameters, self.METHOD, context)
|
||||
field = self.parameterAsString(parameters, self.FIELD, context)
|
||||
|
||||
layer = QgsProcessingUtils.mapLayerFromString(filename, context)
|
||||
field = self.getParameterValue(self.FIELD)
|
||||
method = self.getParameterValue(self.METHOD)
|
||||
|
||||
layer.removeSelection()
|
||||
index = layer.fields().lookupField(field)
|
||||
|
||||
unique = QgsProcessingUtils.uniqueValues(layer, index, context)
|
||||
unique = layer.uniqueValues(index)
|
||||
featureCount = layer.featureCount()
|
||||
|
||||
value = int(self.getParameterValue(self.NUMBER))
|
||||
value = self.parameterAsInt(parameters, self.NUMBER, context)
|
||||
if method == 0:
|
||||
if value > featureCount:
|
||||
raise GeoAlgorithmExecutionException(
|
||||
raise QgsProcessingException(
|
||||
self.tr('Selected number is greater that feature count. '
|
||||
'Choose lesser value and try again.'))
|
||||
else:
|
||||
if value > 100:
|
||||
raise GeoAlgorithmExecutionException(
|
||||
raise QgsProcessingException(
|
||||
self.tr("Percentage can't be greater than 100. Set a "
|
||||
"different value and try again."))
|
||||
value = value / 100.0
|
||||
|
||||
selran = []
|
||||
inFeat = QgsFeature()
|
||||
|
||||
current = 0
|
||||
total = 100.0 / (featureCount * len(unique)) if featureCount else 1
|
||||
|
||||
if not len(unique) == featureCount:
|
||||
for i in unique:
|
||||
features = QgsProcessingUtils.getFeatures(layer, context)
|
||||
FIDs = []
|
||||
for inFeat in features:
|
||||
attrs = inFeat.attributes()
|
||||
if attrs[index] == i:
|
||||
FIDs.append(inFeat.id())
|
||||
current += 1
|
||||
feedback.setProgress(int(current * total))
|
||||
classes = defaultdict(list)
|
||||
|
||||
if method == 1:
|
||||
selValue = int(round(value * len(FIDs), 0))
|
||||
else:
|
||||
selValue = value
|
||||
features = layer.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry).setSubsetOfAttributes([index]))
|
||||
|
||||
if selValue >= len(FIDs):
|
||||
selFeat = FIDs
|
||||
else:
|
||||
selFeat = random.sample(FIDs, selValue)
|
||||
for i, feature in enumerate(features):
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
classes[feature.attributes()[index]].append(feature.id())
|
||||
feedback.setProgress(int(i * total))
|
||||
|
||||
selran = []
|
||||
for subset in classes.values():
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
selValue = value if method != 1 else int(round(value * len(subset), 0))
|
||||
selran.extend(random.sample(subset, selValue))
|
||||
|
||||
selran.extend(selFeat)
|
||||
layer.selectByIds(selran)
|
||||
else:
|
||||
layer.selectByIds(list(range(featureCount))) # FIXME: implies continuous feature ids
|
||||
|
||||
self.setOutputValue(self.OUTPUT, filename)
|
||||
return {self.OUTPUT: parameters[self.INPUT]}
|
||||
|
Loading…
x
Reference in New Issue
Block a user