How do I create a Processing script which asks the user for a layer and then conducts an operation on it?
import processing
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessingAlgorithm,
QgsProcessing,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsVectorLayer)
class testAlg(QgsProcessingAlgorithm):
HEXES = 'HEXES'
OUTPUT = 'OUTPUT'
def tr(self, text):
return QCoreApplication.translate('testalg', text)
def createInstance(self):
return type(self)()
def group(self):
return self.tr('Test')
def groupId(self):
return 'test'
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.HEXES,
self.tr('Input layer'),
[QgsProcessing.TypeVectorAnyGeometry]))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
self.tr('Output'),
QgsProcessing.TypeVectorPolygon))
def name(self):
return 'testalg'
def displayName(self):
return self.tr('Test Algorithm')
def processAlgorithm(self, parameters, context, feedback):
hex_source1 = self.parameterAsSource(parameters, self.HEXES, context)
hex_source2 = QgsVectorLayer('/Users/username/temp/hexes.shp', 'hex_source2', 'ogr')
feedback.pushConsoleInfo(str(type(hex_source1))) # Returns QgsProcessingFeatureSource
feedback.pushConsoleInfo(str(type(hex_source2))) # Returns QgsVectorLayer
processing.run('qgis:fieldcalculator',
{'INPUT':hex_source1, # Dies here as it can't accept a QgsProcessingFeatureSource
'FIELD_NAME':'test',
'FIELD_TYPE':0,
'FIELD_LENGTH':10,
'FIELD_PRECISION':6,
'NEW_FIELD':True,
'FORMULA':'( "c" / sum( "c" )) * 100',
'OUTPUT':'/Users/username/temp/hexes2.shp'},
feedback=feedback,
context=context)
return {}
This code fails at the processing.run
command as it can't accept a QgsProcessingFeatureSource
(hex_source1
) as an input (actual error is Incorrect parameter value for INPUT
). Using hex_source2
works fine as that returns a QgsVectorLayer
which is apparently fine as an input.
I have also tried QgsProcessingParameterVectorLayer
which also seems to give a QgsProcessingFeatureSource
result.
Should I be converting a QgsProcessingFeatureSource
to a QgsVectorLayer
? If so, how? Or is there a simpler way to load a layer for processing that I'm missing?
4 Answers 4
In this case, because the field calculator algorithm requires a vector layer input, you'll need to declare a QgsProcessingParameterVectorLayer parameter as the input for your algorithm (not a feature source).
You'll then need to change
hex_source1 = self.parameterAsSource(parameters, self.HEXES, context)
To
hex_source1 = self.parameterAsVectorLayer(parameters, self.HEXES, context)
This will give you a QgsVectorLayer value for hex_source1, ready for handing off to the field calculator algorithm.
-
Doesn't seem to work. Feedback gives
<class 'NoneType'>
and theprocessing.run
fails due toIncorrect parameter value for INPUT
.Josh– Josh2018年04月25日 15:04:52 +00:00Commented Apr 25, 2018 at 15:04 -
Works fine for me. Thx :-)Sickboy– Sickboy2022年03月05日 08:26:39 +00:00Commented Mar 5, 2022 at 8:26
Keep
hex_source1 = self.parameterAsSource(parameters, self.HEXES, context)
But instead of
'INPUT':hex_source1
use
'INPUT':hex_source1.materialize(QgsFeatureRequest())
(be sur to add QgsFeatureRequest in your imports)
This is confusing, but As pointed out here , you can simply lookup the input layer's value from parameters
hex_source1 = parameters[self.HEXES]
As ndawson pointed out, the qgis:fieldcalculator algorithm needs a VectorLayer. I have modified your code accordingly (also had to change the formulae and output path, and removed hex_source2), and it works for me in QGIS 3.4.
import processing
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessingAlgorithm,
QgsProcessing,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsVectorLayer)
class testAlg(QgsProcessingAlgorithm):
HEXES = 'HEXES'
OUTPUT = 'OUTPUT'
def tr(self, text):
return QCoreApplication.translate('testalg', text)
def createInstance(self):
return type(self)()
def group(self):
return self.tr('Test')
def groupId(self):
return 'test'
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.HEXES,
self.tr('Input layer'),
[QgsProcessing.TypeVectorAnyGeometry]))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
self.tr('Output'),
QgsProcessing.TypeVectorPolygon))
def name(self):
return 'testalg'
def displayName(self):
return self.tr('Test Algorithm')
def processAlgorithm(self, parameters, context, feedback):
hex_source1 = self.parameterAsVectorLayer(parameters, self.HEXES, context)
#hex_source1 = self.parameterAsSource(parameters, self.HEXES, context)
#hex_source2 = QgsVectorLayer('/Users/username/temp/hexes.shp', 'hex_source2', 'ogr')
feedback.pushConsoleInfo(str(type(hex_source1))) # Returns QgsProcessingFeatureSource
#feedback.pushConsoleInfo(str(type(hex_source2))) # Returns QgsVectorLayer
processing.run('qgis:fieldcalculator',
{'INPUT':hex_source1, # Dies here as it can't accept a QgsProcessingFeatureSource
'FIELD_NAME':'test',
'FIELD_TYPE':0,
'FIELD_LENGTH':10,
'FIELD_PRECISION':6,
'NEW_FIELD':True,
'FORMULA':'( "FID" / sum( "FID" )) * 100',
'OUTPUT':'/tmp/test.shp'},
feedback=feedback,
context=context)
return {}