0

I have created a QGIS Graphic Model using the built-in Graphic Modeler. My model is supposed to ask the user for an input layer, an overlay layer, and a field from the overlay layer.

The model then should calculate the area-weighted average of that field for each feature in the input layer. The result will be an input layer with an extra field for the area-weighted average. I have the complete workflow in my mind. Till now I have reached this point, where I want to multiply the field given by the user with the area of the feature in the intersection layer.

enter image description here

enter image description here

I have converted the model to a python script to use the value of the parameter 'Field to Average' in naming my field in the 'Field Calculator' and in calculating the new field. My question is how do I access the value of Field to Average parameter inside my Field Calculator Formula and Field Name. I have tried using parameter(fieldtoaverge) and it is not working. See my comments in the script inside Field Calculator Algorithm

from qgis.core import QgsProcessing
from qgis.core import QgsProcessingAlgorithm
from qgis.core import QgsProcessingMultiStepFeedback
from qgis.core import QgsProcessingParameterVectorLayer
from qgis.core import QgsProcessingParameterField
import processing
class Model(QgsProcessingAlgorithm):
 def initAlgorithm(self, config=None):
 self.addParameter(QgsProcessingParameterVectorLayer('overlaylayer', 'Overlay Layer', types=[QgsProcessing.TypeVectorPolygon], defaultValue=None))
 self.addParameter(QgsProcessingParameterVectorLayer('inputlayer', 'Input Layer', types=[QgsProcessing.TypeVectorPolygon], defaultValue=None))
 self.addParameter(QgsProcessingParameterField('fieldtoaverage', 'Field to Average', type=QgsProcessingParameterField.Numeric, parentLayerParameterName='overlaylayer', allowMultiple=False, defaultValue=None))
 def processAlgorithm(self, parameters, context, model_feedback):
 # Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the
 # overall progress through the model
 feedback = QgsProcessingMultiStepFeedback(2, model_feedback)
 results = {}
 outputs = {}
 # Intersection
 alg_params = {
 'INPUT': parameters['inputlayer'],
 'INPUT_FIELDS': None,
 'OVERLAY': parameters['inputlayer'],
 'OVERLAY_FIELDS': None,
 'OVERLAY_FIELDS_PREFIX': '',
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['Intersection'] = processing.run('native:intersection', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(1)
 if feedback.isCanceled():
 return {}
 # Field calculator
 alg_params = {
 'FIELD_LENGTH': 10,
 'FIELD_NAME': 'Field Avg * Area', # I need to name it with 'field selected by user * Area'
 'FIELD_PRECISION': 3,
 'FIELD_TYPE': 0,
 'FORMULA': ' parameter(fieldtoaverage) * $area ', # This is not working, how do I acess the field selected by the user here
 'INPUT': outputs['Intersection']['OUTPUT'],
 'NEW_FIELD': True,
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['FieldCalculator'] = processing.run('qgis:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 return results
 def name(self):
 return 'model'
 def displayName(self):
 return 'model'
 def group(self):
 return ''
 def groupId(self):
 return ''
 def createInstance(self):
 return Model()
GforGIS
3,3954 gold badges23 silver badges40 bronze badges
asked Mar 3, 2020 at 23:18
4
  • 1
    The parameters in a QGIS processingscript are organized in a python dictionary (key-value pairs). To access the values of a dictionary you have to use a syntax like: value = mydictionary['key'] , so in your case it should be parameters['fieldtoaverage'] Commented Mar 4, 2020 at 5:20
  • If in my script I allow multiple field selection for the 'Field to Average' input parameter, how will I access the first, second parameters and so on? Commented Mar 4, 2020 at 15:17
  • Awaiting your reply @eurojam Commented Mar 9, 2020 at 2:15
  • 1
    you can put a print(parameters) into your script and look how the dictionary will be organized. Commented Mar 10, 2020 at 6:30

1 Answer 1

1

I have modified your algorithm to make it run. The code below runs, and produces an output layer where the new field has the name that you specified. Could you test it?

from qgis.core import QgsProcessing
from qgis.core import QgsProcessingAlgorithm
from qgis.core import QgsProcessingMultiStepFeedback
from qgis.core import QgsProcessingParameterVectorLayer
from qgis.core import QgsProcessingParameterField
from qgis.core import QgsProcessingParameterVectorDestination
import processing
class Model(QgsProcessingAlgorithm):
def initAlgorithm(self, config=None):
 self.addParameter(QgsProcessingParameterVectorLayer('overlaylayer', 'Overlay Layer', types=[QgsProcessing.TypeVectorPolygon], defaultValue=None))
 self.addParameter(QgsProcessingParameterVectorLayer('inputlayer', 'Input Layer', types=[QgsProcessing.TypeVectorPolygon], defaultValue=None))
 self.addParameter(QgsProcessingParameterVectorDestination('OUTPUT', 'Model output'))
 self.addParameter(QgsProcessingParameterField('fieldtoaverage', 'Field to Average', type=QgsProcessingParameterField.Numeric, parentLayerParameterName='overlaylayer', allowMultiple=False, defaultValue=None))
def processAlgorithm(self, parameters, context, model_feedback):
 # Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the
 # overall progress through the model
 feedback = QgsProcessingMultiStepFeedback(2, model_feedback)
 results = {}
 outputs = {}
 # Intersection
 alg_params = {
 'INPUT': parameters['inputlayer'],
 'INPUT_FIELDS': None,
 'OVERLAY': parameters['overlaylayer'],
 'OVERLAY_FIELDS': None,
 'OVERLAY_FIELDS_PREFIX': '',
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['Intersection'] = processing.run('native:intersection', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(1)
 if feedback.isCanceled():
 return {}
 # Field calculator
 alg_params = {
 'FIELD_LENGTH': 10,
 'FIELD_NAME': parameters['fieldtoaverage'] + ' * Area', # I need to name it with 'field selected by user * Area'
 'FIELD_PRECISION': 3,
 'FIELD_TYPE': 0,
 'FORMULA': '"' + parameters['fieldtoaverage'] + '" * $area',
 'INPUT': outputs['Intersection']['OUTPUT'],
 'NEW_FIELD': True,
 'OUTPUT': parameters['OUTPUT']
 }
 calcoutput = processing.run('qgis:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 results['OUTPUT'] = calcoutput['OUTPUT']
 return results
def name(self):
 return 'model'
def displayName(self):
 return 'model'
def group(self):
 return ''
def groupId(self):
 return ''
def createInstance(self):
 return Model()

I have added a parameter for the output, used parameters[] for accessing all the parameters, and changed 'inputlayer' to 'overlaylayer' in the Intersection parameters.

answered Mar 4, 2020 at 8:10
4
  • Ok. So I understood all your changes, I ran the model and it worked fine when the name of the input field was CN, but it is giving the following error for a different field whose name contain % sign i.e. Imp%. I changed the name to Imper and it worked fine for 'Imper' as well. Any idea why the % sign is causing this error and how to avoid it? No root node! Parsing failed? Commented Mar 4, 2020 at 15:25
  • BTW the error is in the formula because field name is getting generated properly in the output layer. Commented Mar 4, 2020 at 15:27
  • awaiting your reply @Havard Tveite Commented Mar 9, 2020 at 2:16
  • 1
    @Someone191, the problem was your % character. If not escaped, it is taken to be the "remainder of division" operator, and the formulae will fail. I have modified the code by "protecting" the field name with '"'. I have tested it with a field named "Imp%", and it works now. Commented May 30, 2020 at 13:15

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.