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.
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()