1

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

The model then should calculate the area-weighted average of those fields for each feature in the input layer. The result will be an input layer with extra fields for each area-weighted average.

enter image description here

I have realized that the field input can't be used in graphic modeller and I have to turn it into a python script to perform this task. I am adding the script here. What I am having trouble is with how to use the input from the user in my field calculations and field names.

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 QgsProcessingParameterFeatureSink
import processing
class FutureLuHsg(QgsProcessingAlgorithm):
 def initAlgorithm(self, config=None):
 self.addParameter(QgsProcessingParameterVectorLayer('luhsgexisting', 'LU HSG', types=[QgsProcessing.TypeVectorPolygon], defaultValue=None))
 self.addParameter(QgsProcessingParameterVectorLayer('parcels', 'Parcels', types=[QgsProcessing.TypeVectorPolygon], defaultValue=None))
 self.addParameter(QgsProcessingParameterField('fieldtoaverage1', 'Field to Average', type=QgsProcessingParameterField.Numeric, parentLayerParameterName='luhsgexisting', allowMultiple=True, defaultValue=None))
 self.addParameter(QgsProcessingParameterFeatureSink('Joined', 'Joined', optional=True, type=QgsProcessing.TypeVectorAnyGeometry, createByDefault=True, defaultValue=None))
 self.addParameter(QgsProcessingParameterFeatureSink('Final', 'Final', type=QgsProcessing.TypeVectorAnyGeometry, createByDefault=True, defaultValue=None))
 self.addParameter(QgsProcessingParameterFeatureSink('Stats', 'Stats', type=QgsProcessing.TypeVectorAnyGeometry, createByDefault=True, 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(6, model_feedback)
 results = {}
 outputs = {}
 # Field calculator
 alg_params = {
 'FIELD_LENGTH': 10,
 'FIELD_NAME': 'FID_Parcels',
 'FIELD_PRECISION': 3,
 'FIELD_TYPE': 1,
 'FORMULA': '$id',
 'INPUT': parameters['parcels'],
 'NEW_FIELD': True,
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['FieldCalculator'] = processing.run('qgis:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(1)
 if feedback.isCanceled():
 return {}
 # Intersection
 alg_params = {
 'INPUT': outputs['FieldCalculator']['OUTPUT'],
 'INPUT_FIELDS': None,
 'OVERLAY': parameters['luhsgexisting'],
 'OVERLAY_FIELDS': parameters['fieldtoaverage1'],
 '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(2)
 if feedback.isCanceled():
 return {}
 # Field calculator 2
 alg_params = {
 'FIELD_LENGTH': 10,
 'FIELD_NAME': 'Field1*Area',
 'FIELD_PRECISION': 2,
 'FIELD_TYPE': 0,
 'FORMULA': ' \"fieldtoaverage\" * $area',
 'INPUT': outputs['Intersection']['OUTPUT'],
 'NEW_FIELD': True,
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['FieldCalculator2'] = processing.run('qgis:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(3)
 if feedback.isCanceled():
 return {}
 # Statistics by categories
 alg_params = {
 'CATEGORIES_FIELD_NAME': 'FID_Parcels',
 'INPUT': outputs['FieldCalculator2']['OUTPUT'],
 'VALUES_FIELD_NAME': 'Field1*Area',
 'OUTPUT': parameters['Stats']
 }
 outputs['StatisticsByCategories'] = processing.run('qgis:statisticsbycategories', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 results['Stats'] = outputs['StatisticsByCategories']['OUTPUT']
 feedback.setCurrentStep(4)
 if feedback.isCanceled():
 return {}
 # Join attributes by field value
 alg_params = {
 'DISCARD_NONMATCHING': False,
 'FIELD': 'FID_Parcels',
 'FIELDS_TO_COPY': 'SUM',
 'FIELD_2': 'FID_Parcels',
 'INPUT': outputs['FieldCalculator']['OUTPUT'],
 'INPUT_2': outputs['StatisticsByCategories']['OUTPUT'],
 'METHOD': 1,
 'PREFIX': 'Stats_',
 'OUTPUT': parameters['Joined']
 }
 outputs['JoinAttributesByFieldValue'] = processing.run('native:joinattributestable', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 results['Joined'] = outputs['JoinAttributesByFieldValue']['OUTPUT']
 feedback.setCurrentStep(5)
 if feedback.isCanceled():
 return {}
 # Field calculator 3
 alg_params = {
 'FIELD_LENGTH': 10,
 'FIELD_NAME': 'Field1_Weighted',
 'FIELD_PRECISION': 3,
 'FIELD_TYPE': 0,
 'FORMULA': ' \"Statssum\" / $area',
 'INPUT': outputs['JoinAttributesByFieldValue']['OUTPUT'],
 'NEW_FIELD': True,
 'OUTPUT': parameters['Final']
 }
 outputs['FieldCalculator3'] = processing.run('qgis:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 results['Final'] = outputs['FieldCalculator3']['OUTPUT']
 return results
 def name(self):
 return 'Future LU HSG'
 def displayName(self):
 return 'Future LU HSG'
 def group(self):
 return 'QGIS Tools'
 def groupId(self):
 return 'QGIS Tools'
 def createInstance(self):
 return FutureLuHsg()
Kadir Şahbaz
78.6k57 gold badges260 silver badges407 bronze badges
asked Feb 19, 2020 at 23:40

1 Answer 1

2

You say: "What I am having trouble is with how to use the input from the user in my field calculations and field names".

Could you explain more about the trouble you are experiencing?

About processing parameter / user input

You access the user input using parameters[] and output[]. That is fine, but you can also access parameters as described in the QGIS user manual. Have a look at Writing new Processing algorithms as Python scripts.

Some examples from the documentation. To get a feature source:

 input_featuresource = self.parameterAsSource(parameters,
 'INPUT',
 context)

To get a double:

 doublepar = self.parameterAsDouble(parameters, 'BUFFERDIST',
 context)

I guess you can see the pattern :-). What you do here is to assign the values of your input parameters to variables for using them in your script. Place these early in your ProcessAlgorithm method (before you need them for your calculations).

Regarding your specific question

To access the input vector field you can use parameters['fieldtoaverage1']. Some examples from your code:

 'FIELD_NAME': parameters['fieldtoaverage1'] + '*Area',
 'FORMULA': parameters['fieldtoaverage1'] + ' * $area',
answered Feb 20, 2020 at 0:33
3
  • Thanks, I have tried to read the documentation but I am unable to find the answer to this. How can I access the fieldtoaverage1 value in the Field Calculator 2 formula line? Any help specific to this will be appreciated Commented Feb 27, 2020 at 21:40
  • I realized that my question is not specific enough. I have posted a new question with fewer details and being more specific. gis.stackexchange.com/questions/352823/… I will delete this question once you reply there. Sorry for the inconvinience. Commented Mar 3, 2020 at 23:20
  • I have provided an answer to the new question. The answer includes code (modification of code in your question). Commented Mar 4, 2020 at 8:18

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.