11

When I use "Update existing fields" in the Field Calculator in QGIS 3.16.0-Hannover, it takes only a second to change all the values in a attribute field to the same value. However when I try to do that with PyQGIS, QGIS crashes.

I have a layer with line geometry with 82800 features inside. I want to change all feature's value inside "visited" column to '0'. Here is how I try to do that:

layer = iface.activeLayer()
lines = [feat for feat in layer.getFeatures()]

layer.startEditing()

for line in lines:
    line["visited"] = 0
    layer.updateFeature(line)

layer.commitChanges()

Can I do that like I do that with field calculator via using PyQGIS (with expressions or something)?

0

1 Answer 1

14

Use layer.dataProvider().changeAttributeValues() method instead of layer.updateFeature(). In this case you don't need to start an edit mode.

import time
    
layer = iface.activeLayer()    
visited_index = layer.fields().indexFromName("visited")
attr_map = {}
new_value = 5

tic = time.perf_counter() ###
for line in layer.getFeatures():
    attr_map[line.id()] = {visited_index: new_value}

layer.dataProvider().changeAttributeValues(attr_map)
toc = time.perf_counter() ###

print(f"{toc - tic:0.4f} seconds")

Using dictionary comprehension instead of for loop is more convenient to minimize the script.

layer = iface.activeLayer()    
i = layer.fields().indexFromName("visited") # index of the field

attr_map = {line.id(): {i: 5} for line in layer.getFeatures()} # comprehension    
layer.dataProvider().changeAttributeValues(attr_map)
5
  • 1
    It took 3 seconds for 100.000 features in my computer. Commented Dec 6, 2020 at 1:05
  • 2
    I know some people find comprehensions obtuse, but in this particular case it arguably makes the intent clearer to build attr_map using a dict comprehension, e.g.: attr_map = {feat.id(): {visited_index: 5} for feat in layer.getFeatures()}.
    – FeRD
    Commented Dec 6, 2020 at 13:40
  • 1
    @FeRD Yes, thank you. Using comprehension is more convenient. Commented Dec 6, 2020 at 16:13
  • @KadirŞahbaz does the geometry column have an index so it can be set in a similar way using a dictionary?
    – Bera
    Commented Aug 8, 2021 at 17:52
  • 1
    @BERA I don't think there is an index for the geometry in QGIS unlike in ArcGIS. changeGeometryValues can be used. Ex: layer.dataProvider().changeGeometryValues(geom_attr_map) Commented Aug 8, 2021 at 18:04

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.