2

Does anyone know how I can turn this console script into a script that I can integrate into the processing toolbox? I tried a few options, but I don't do very well in python, and I always get stuck.

# Change your settings here:
layername = 'line' 
triggerfield = 'Trigger' # field must already exist
groupfieldname = 'mygroup' # will be added if does not exist
newlineindicator = 1

#####
# no changes needed below #
#####
layer = QgsProject.instance().mapLayersByName(layername)[0] # get the layer
layer.startEditing() # start editing the layer
layer.dataProvider().addAttributes([QgsField(groupfieldname,QVariant.Int)]) # add a group field
layer.commitChanges() # save new added field to prevent crash when searching for it later
layer.startEditing() # start editing the layer again
groupid = 0 # initialize groupid
fieldindex = layer.fields().indexFromName(groupfieldname) # get fieldindex of groupfield

for feat in layer.getFeatures(): # itereate over layer
    if feat[triggerfield] == newlineindicator: # if a new trigger appears, increase groupcounter
        groupid += 1
    attrs = { fieldindex : groupid } # prepare attributes
    layer.dataProvider().changeAttributeValues({ feat.id() : attrs }) # assign current groupid to current feature
layer.commitChanges() # save changes

What do you think? Can it be transformed into a function, with input and output parameters?

EDIT:

I got stuck at this point. Does anyone know how I can solve this script? How should I define "newlineindicator = 1" and "groupid = 0"?

# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication, QVariant
from qgis.core import (QgsProcessing,
                       QgsFeatureSink,
                       QgsFeature,
                       QgsField,
                       QgsFields,
                       QgsProcessingException,
                       QgsProcessingAlgorithm,
                       QgsProcessingParameterString,
                       QgsProcessingParameterNumber,
                       QgsProcessingParameterEnum,
                       QgsProcessingParameterFeatureSource,
                       QgsProcessingParameterFeatureSink,
                       QgsProcessingParameterField,
                       )
import processing
class MergingMultipleLinesByValueField(QgsProcessingAlgorithm):
    INPUT = 'INPUT'
    OUTPUT = 'OUTPUT'
    TRIGGER_FIELD = 'trigger_field'
    groupfieldname = 'mygrup'

    def tr(self, string):
        return QCoreApplication.translate('Processing', string)

    def createInstance(self):
        return MergingMultipleLinesByValueField()

    def name(self):
        return 'myscript'

    def displayName(self):
        return self.tr('My Script')

    def group(self):
        return self.tr('Example scripts')

    def groupId(self):
        return 'examplescripts'

    def shortHelpString(self):
        return self.tr("Example algorithm short description")

    def initAlgorithm(self, config=None):
        self.addParameter(
            QgsProcessingParameterFeatureSource(
                self.INPUT,
                self.tr('Input layer'),
                [QgsProcessing.TypeVectorAnyGeometry]
            )
        )

        
        self.addParameter(
            QgsProcessingParameterField(
                self.TRIGGER_FIELD,
                'Choose Trigger Field',
                '', 
                self.INPUT
            )
        )

        self.addParameter(
            QgsProcessingParameterField(
                self.groupfieldname,
                'Choose Trigger Field',
                '', 
                self.INPUT
            )
        ) 

        self.addParameter(
            QgsProcessingParameterFeatureSink(
                self.OUTPUT,
                self.tr('Output layer')
            )
        )

    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(
            parameters,
            self.INPUT,
            context
        )
        
        trigger = self.parameterAsString(
            parameters,
            self.TRIGGER_FIELD,
            context)
            
        groupfield = self.parameterAsString(
            parameters,
            self.groupfieldname,
            context)
        
        if source is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
            
        fields = QgsFields()
        fields.append(QgsField(trigger, QVariant.String))

        (sink, dest_id) = self.parameterAsSink(
            parameters,
            self.OUTPUT,
            context,
            source.fields(),
            source.wkbType(),
            source.sourceCrs()
        )

        feedback.pushInfo('Extracting unique values from dissolve_field and computing sum')
        features = source.getFeatures()
        groupid = set(f[trigger] for f in features)
        groupid = source.fields().indexFromName(trigger)
        fieldindex = source.fields().indexFromName(groupfieldname) # get fieldindex of groupfield
        newlineindicator = 1
        groupid = 0
        
        for feat in source.getFeatures(): # itereate over layer
            if feat[trigger] == newlineindicator: # if a new trigger appears, increase groupcounter
                    groupid += 1
            attrs = { fieldindex : groupid } # prepare attributes
            layer.dataProvider().changeAttributeValues({ feat.id() : attrs }) # assign current groupid to current feature
        layer.commitChanges() # save changes
        
        

        return {self.OUTPUT: dest_id}
4

1 Answer 1

1

This should do it:

from PyQt5.QtCore import QCoreApplication, QVariant
from qgis.core import (QgsField, QgsFeature, QgsProcessing, QgsExpression, QgsGeometry, QgsPoint, QgsFields, QgsWkbTypes,
                       QgsFeatureSink, QgsFeatureRequest, QgsProcessingAlgorithm,
                       QgsProcessingParameterFeatureSink, QgsProcessingParameterField, QgsProcessingParameterFeatureSource, QgsProcessingParameterEnum, QgsProcessingParameterString, QgsProcessingParameterNumber)

class AddGroupByIndicator(QgsProcessingAlgorithm):
    SOURCE_LYR = 'SOURCE_LYR'
    TRIGGER_FIELD = 'TRIGGER_FIELD'
    GROUP_IDFIELD = 'GROUP_IDFIELD'
    INDICATOR_VALUE = 'INDICATOR_VALUE'
    OUTPUT = 'OUTPUT'

    def initAlgorithm(self, config=None):
        
        self.addParameter(
            QgsProcessingParameterFeatureSource(
                self.SOURCE_LYR, self.tr('Source'))) # Take any source layer
        self.addParameter(
            QgsProcessingParameterField(
                self.TRIGGER_FIELD, self.tr('Trigger Field indicating a new Group'),'Trigger','SOURCE_LYR')) # Choose the Trigger field of the source layer, default if exists is 'Trigger'
        self.addParameter(
            QgsProcessingParameterString(
                self.GROUP_IDFIELD, self.tr('Name of new generated GroupID Field'),'groupid')) # String of the new added fieldname, default is 'groupid'
        self.addParameter(
            QgsProcessingParameterNumber(
                self.INDICATOR_VALUE, self.tr('Number indicating a new Group'),0,1)) # Indicator as number. 0=Int, 1 would be double; 1=default number
        self.addParameter(
            QgsProcessingParameterFeatureSink(
                self.OUTPUT, self.tr('SourceWithGroupID'))) # Output

    def processAlgorithm(self, parameters, context, feedback):
        # Get Parameters and assign to variable to work with
        source_layer = self.parameterAsLayer(parameters, self.SOURCE_LYR, context)
        triggerfield = self.parameterAsString(parameters, self.TRIGGER_FIELD, context)
        groupfieldname = self.parameterAsString(parameters, self.GROUP_IDFIELD, context)
        newlineindicator = self.parameterAsInt(parameters, self.INDICATOR_VALUE, context)
        
        groupid = 0 # initialize groupid counter
        
        total = 100.0 / source_layer.featureCount() if source_layer.featureCount() else 0 # Initialize progress for progressbar
        
        fields = source_layer.fields() # get all fields of the sourcelayer
        fields.append(QgsField(groupfieldname, QVariant.Int, len=20)) # add a new field to this list
        
        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, source_layer.wkbType(),
                                               source_layer.sourceCrs())
                                               
        for current, feat in enumerate(source_layer.getFeatures()): # iterate over source 
            if feat[triggerfield] == newlineindicator: # if trigger appears increase groupcounter
                groupid += 1
            new_feat = QgsFeature(fields) # copy source fields + appended
            idx = 0 # reset attribute fieldindex
            for attr in feat.attributes(): # iterate over attributes of source layer for the current feature
                new_feat[idx] = attr # copy attribute values over to the new layer
                idx += 1 # increase fieldindex counter
            new_feat[groupfieldname] = groupid # assign the groupid
            new_feat.setGeometry(feat.geometry()) # copy over the geometry of the source feature
            
            sink.addFeature(new_feat, QgsFeatureSink.FastInsert) # add feature to the output
            
            if feedback.isCanceled(): # Cancel algorithm if button is pressed
                break
            
            feedback.setProgress(int(current * total)) # Set Progress in Progressbar

        return {self.OUTPUT: dest_id} # Return result of algorithm



    def tr(self, string):
        return QCoreApplication.translate('Processing', string)

    def createInstance(self):
        return AddGroupByIndicator()

    def name(self):
        return 'AddGroupByIndicator'

    def displayName(self):
        return self.tr('Add group by indicator field')

    def group(self):
        return self.tr('FROM GISSE')

    def groupId(self):
        return 'from_gisse'

    def shortHelpString(self):
        return self.tr('This Algorithm adds a new group id found by a trigger')
1
  • 1
    The latest version is excellent. I can't believe you solved it nicely. Thank you for your help. The fact that you commented on each line helps me a lot to learn how to do it. You are awesome.
    – Tony Pasca
    Dec 18, 2020 at 20:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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