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)?
1 Answer 1
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)
-
1It took 3 seconds for 100.000 features in my computer.Kadir Şahbaz– Kadir Şahbaz2020年12月06日 01:05:04 +00:00Commented Dec 6, 2020 at 1:05
-
2I 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– FeRD2020年12月06日 13:40:32 +00:00Commented Dec 6, 2020 at 13:40 -
1@FeRD Yes, thank you. Using comprehension is more convenient.Kadir Şahbaz– Kadir Şahbaz2020年12月06日 16:13:59 +00:00Commented 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– Bera2021年08月08日 17:52:20 +00:00Commented 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)
Kadir Şahbaz– Kadir Şahbaz2021年08月08日 18:04:57 +00:00Commented Aug 8, 2021 at 18:04
Explore related questions
See similar questions with these tags.