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
13

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. Dec 6 '20 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
    Dec 6 '20 at 13:40
  • 1
    @FeRD Yes, thank you. Using comprehension is more convenient. Dec 6 '20 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
    Aug 8 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) Aug 8 at 18:04

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.