3

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?

asked Apr 24, 2018 at 15:05

4 Answers 4

5

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.

answered Apr 24, 2018 at 20:28
2
  • Doesn't seem to work. Feedback gives <class 'NoneType'> and the processing.run fails due to Incorrect parameter value for INPUT. Commented Apr 25, 2018 at 15:04
  • Works fine for me. Thx :-) Commented Mar 5, 2022 at 8:26
1

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)

answered May 4, 2018 at 15:30
0

This is confusing, but As pointed out here , you can simply lookup the input layer's value from parameters

hex_source1 = parameters[self.HEXES]
answered Feb 24, 2019 at 13:27
0

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 {}
answered Mar 27, 2019 at 13:58

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.