pyqgis – Filling New Field with Values Based on Other Fields and Lookup Table in QGIS

numpypyqgis

I am trying to use Python for QGIS to add values to new fields in an attribute table based on existing fields and values in a lookup table.

Attribute table I wish to modify (with example rows):

farm      | ref_1 | ref_2 | newField_1 | newField_2
Macdonald | seeds | veg   | <Null>     | <Null>
Fred      | seeds | fruit | <Null>     | <Null>
Bob       | seeds | fruit | <Null>     | <Null>

Lookup table:

ref_1, ref_2, lookup_1, lookup_2
seeds, fruit, 13, 4
seeds, veg, 10, 3

Assuming newFields 1 & 2 have been added to the attribute table, my code is as follows:

aLayer =  qgis.utils.iface.activeLayer()
provider = aLayer.dataProvider()

lookup_table = np.loadtxt(r'filepath\myfile.csv',dtype=str,delimiter=',',skiprows=1)
aLayer.startEditing

for feature in aLayer.getFeatures():
    for i in lookup_table:
        if i[0] == feature['ref_1'] and i[1] == feature['ref_2']:
            provider.changeAttributeValues({feature.id() : {provider.fieldNameMap()['newField_1'] : i[2]}})
            provider.changeAttributeValues({feature.id() : {provider.fieldNameMap()['newField_2'] : i[3]}})
            aLayer.updateFeature(feature)
aLayer.commitChanges()

After running the code, the newFields 1 & 2 remain null.

Referring to Setting feature attribute by name via QGIS python api? I can get provider.changeAttributeValues() to work based off of fields within the same table (e.g., changing newField_1's value to that of farm); however, if I reference a lookup table, newFields 1 & 2 remain null.

Best Answer

Probably is related... but you are mixing QgsVectorLayer commit with QgsVectorDataProvider methods. You have to avoid mixing because they work on different workflows!

using dataprovider you write directly on the file using dataprovider interface... and you write it every updateFeature (well could be managed a cache depending on provider... but it's leaved to provider)

using aLayer.startEditing and commitChanges you are using QgsVectorLayer interface that manage Undo/redo with a QgsEditingBuffer... during commmit, the vector layer interface with dataprovider writes (and optimize) changes available in the editing buffer.

probably the commit from layer lever interfere with the changes already done with provider... overwriting them (the layer is unchanghed in the memory cache... but only in the file thanks to provider)

possible solution

1) remove startEditing and commit and use only dataProvider 2) remove dataprovider methods and use qgsvectorlayer method to modifye features... depending if you want a rollback in case of errers, it's more safe using this method.

regards,

Related Question