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()
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'] – eurojam Mar 4 '20 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? – ar-siddiqui Mar 4 '20 at 15:17
  • Awaiting your reply @eurojam – ar-siddiqui Mar 9 '20 at 2:15
  • 1
    you can put a print(parameters) into your script and look how the dictionary will be organized. – eurojam Mar 10 '20 at 6:30
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.

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? – ar-siddiqui Mar 4 '20 at 15:25
  • BTW the error is in the formula because field name is getting generated properly in the output layer. – ar-siddiqui Mar 4 '20 at 15:27
  • awaiting your reply @Havard Tveite – ar-siddiqui Mar 9 '20 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. – Håvard Tveite May 30 '20 at 13:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.