4

I would like to iterate over N unknown attributes in the QGIS Graphical Modeler. For example dividing all attributes in an input layer by its area to create an area weighting.

I realise it could be done with Python, but I'm wondering if there is some clever way to accomplish this with out-of-the-box tools.

5
  • You can do that by using the Field Calculator.
    – geoSAM
    Oct 17, 2019 at 7:12
  • 1
    @geoSAM Okey, interesting, could you write an example as an answer?
    – hexamon
    Oct 17, 2019 at 7:18
  • One of the inputs is called "field mapper," which sounds promising. I can't find any documentation or figure out how it works though.
    – csk
    Oct 17, 2019 at 16:08
  • Or you could add as many vector field inputs as the maximum possible number of fields, then manually select them when you run the model.
    – csk
    Oct 17, 2019 at 16:08
  • see if this helps you gis.stackexchange.com/questions/292324/… Oct 18, 2019 at 14:36

2 Answers 2

2

You can do that by using the sum function from the Field Calculator. Specifically for your case let's assume that you have a polygon vector with an attribute "AREA" representing the area of each polygon. In Field Calculator you create a new field with expression : "AREA"/sum("AREA")

1
  • Ah, the key word in my question is unknown however. I want to iterate over all attributes in a layer without knowing their names and data types. So basically a for each loop where I do something with each attribute in a layer, and where the number of attributes and their names are unknown.
    – hexamon
    Oct 18, 2019 at 7:18
1

I ended up writing a Python script after all. It's available here:

https://github.com/hexamon/qgispythonprocessing/blob/master/math_on_all_fields.py

If someone answers with a non-Python solution that works I will accept that instead.

Here is the relevant logic in the script:

    op = self.parameterAsEnum(parameters, self.OPERATION,context) #Math operation type fetched from enumerated list parameter
    col = self.parameterAsFields(parameters, self.DIVCOL,context)[0] #Column for operation

    for current, feature in enumerate(features):

        # Stop the algorithm if cancel button has been clicked
        if feedback.isCanceled():
            break

        #Iterate over all fields
        for current, attr in enumerate(feature.fields()):

            #Don't process the column used for the operation
            if current != feature.fieldNameIndex(col):

                #Current attribute in iteration
                c = feature.attribute(feature.fieldNameIndex(attr.name()))
                #Column to use for operation
                d = feature.attribute(feature.fieldNameIndex(col))

                if(attr.isNumeric() == TRUE):

                    if(op == 0):
                        newVal = c * d
                    elif(op == 1):
                        newVal = c / d
                    elif(op == 2):
                        newVal = c + d
                    elif(op == 3):
                        newVal = c - d

                    feature.setAttribute(current, newVal)

Your Answer

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

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