PyQGIS – Updating Attribute Field with Values from List Calculation using PyQGIS

editingfields-attributesiteratorpyqgisupdate

I have a shapefile and I need to update a field with calculation results. In the calculation I'm iterating through two list with equal items as features of the shapefile. The sum of the list items gets multiplied with an integer value (constant). The field name which needs to be updated is "SH".

Here is how I tried solving it with some example data:

a = [134.24, 134.24, 134.24, 134.99]
b = [58.848430067837946, 70.46615125391358, 63.02756211443306, 60.662300968221174]
c = 0.6673779977746334

newlayer = iface.addVectorLayer(outfile_rel_revised,"", "ogr")
newlayer.setCrs(crsSrc)

with edit(newlayer):
    for rel_feature in newlayer.getFeatures():
        for i in a:
            for j in b:
                rel_feature['SH'] = ((i + j)* c)
                newlayer.updateFeature(rel_feature)
                break 

If I run this, I get no error but the field is not updated. For example the calculation for feature 1 should look like this:
(134.24 + 58.848430067837946)*0.6673779977746334

The finished result should look like this:

enter image description here

Best Answer

Try this logic:

a = [134.24, 134.24, 134.24, 134.99]
b = [58.848430067837946, 70.46615125391358, 63.02756211443306, 60.662300968221174]
c = 0.6673779977746334

newlayer = iface.activeLayer()

with edit(newlayer):
    for i,rel_feature in enumerate(newlayer.getFeatures()):
        rel_feature['SH'] = round((a[i] + b[i])*c,2)
        newlayer.updateFeature(rel_feature)

Make sure your file is not write protected and the field (SH) is of type real.

This should actually work. If for some reason it does not update the file, you can give changeAttributeValue() method a try:

a = [134.24, 134.24, 134.24, 134.99]
b = [58.848430067837946, 70.46615125391358, 63.02756211443306, 60.662300968221174]
c = 0.6673779977746334

newlayer = iface.activeLayer()

with edit(newlayer):
    for i,rel_feature in enumerate(newlayer.getFeatures()):
        result = round((a[i] + b[i])*c,2)
        newlayer.changeAttributeValue(rel_feature.id(), newlayer.fields().indexOf('SH'), result)

With this kind of logic an order by request might make sense:

a = [134.24, 134.24, 134.24, 134.99]
b = [58.848430067837946, 70.46615125391358, 63.02756211443306, 60.662300968221174]
c = 0.6673779977746334

newlayer = iface.activeLayer()

request = QgsFeatureRequest()
clause = QgsFeatureRequest.OrderByClause('id', ascending=True)
orderby = QgsFeatureRequest.OrderBy([clause])
request.setOrderBy(orderby)

with edit(newlayer):
    for i,rel_feature in enumerate(newlayer.getFeatures(request)):
        result = round((a[i] + b[i])*c,2)
        newlayer.changeAttributeValue(rel_feature.id(), newlayer.fields().indexOf('SH'), result)