6

I am using QGIS 3.2.1 Bonn 64 bit on Windows 10. I would like to loop through a list of field names and perform calculations on each field. Only the first loop in the iteration performs any calculations. The rest are skipped.

result_path = r"D:\QGIS\hex_results.geojson"

tracks = QgsProject.instance().mapLayersByName("patrol_tracks")[0]
result = QgsProject.instance().mapLayersByName("hex_results")[0]

t = tracks.getFeatures()
r = result.getFeatures()

r_prov = result.dataProvider()
r_fields = r_prov.fieldNameMap()

months = [x for x in processing.run("qgis:listuniquevalues", {'INPUT':tracks,'FIELDS':"Month_Year",'OUTPUT':'u'})['UNIQUE_VALUES'].split(";")]

for m in months:
    result.startEditing()
    field_index = result.fields().lookupField(m)
    print (m)
    print (field_index)
    a = {field_index : 0}
    for feat in r:
        fid = feat.id()
        r_prov.changeAttributeValues({fid : a})

    result.commitChanges()

The print calls work for every list item but the field attributes are only altered for the first iteration.

Another method I have tried (using the same variable names as above) is:

for m in months:
    processing.run('qgis:fieldcalculator', {'INPUT':result, 'FIELD_NAME':m, 'FIELD_TYPE':1, 'FIELD_LENGTH':10, 'FIELD_PRECISION':0, 'NEW_FIELD': False, 'FORMULA':'0', 'OUTPUT':result_path})

But with the same result - only the first field in the list is calculated. This code will be part of a more complex script that calculates field values based on the intersection of selected features - which is more or less working up until this point.

Any suggestions? I wondered if the dataProvider needs to be refreshed or updated after each iteration but commitChanges(), added later, doesn't seem to have any effect.

0

1 Answer 1

9

The QgsFeatureIterator is closed after returning all features.

Example:

>>layer = iface.activeLayer()
>>feats = layer.getFeatures()

>>[f['GRID_ID'] for f in feats]
['AP7', 'AP8', 'AP9', 'AP3', 'AP4', 'AP5', 'AP6', 'AP1', 'AP2']

>>[f['GRID_ID'] for f in feats]
[] #No more features are return after used once

>>feats = layer.getFeatures() #Recreate it
>>[f['GRID_ID'] for f in feats]
['AP7', 'AP8', 'AP9', 'AP3', 'AP4', 'AP5', 'AP6', 'AP1', 'AP2']

So in your case recreate it for each iteration:

...
for m in months:
    result.startEditing()
    field_index = result.fields().lookupField(m)
    print (m)
    print (field_index)
    a = {field_index : 0}
    for feat in r:
        fid = feat.id()
        r_prov.changeAttributeValues({fid : a})
    result.commitChanges()
    r = result.getFeatures()
0

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.