3

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.

  • You can do that by using the Field Calculator. – geoSAM Oct 17 '19 at 7:12
  • 1
    @geoSAM Okey, interesting, could you write an example as an answer? – hexamon Oct 17 '19 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 '19 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 '19 at 16:08
  • see if this helps you gis.stackexchange.com/questions/292324/… – Herbert Santos Oct 18 '19 at 14:36
1

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")

  • 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 '19 at 7:18
0

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, privacy policy and cookie policy

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