Previously, we already covered how to create vector layers, how to add fields to their attribute table, and how to set the field values. This time, instead of setting the fields to some preset values, we’ll be using QGIS expressions to compute the values.
First, let’s create a vector layer with three features! The layer creation code reuses things we’ve already covered in previous examples:
from qgis.PyQt.QtCore import QVariant vl = QgsVectorLayer("Point", "Companies", "memory") pr = vl.dataProvider() pr.addAttributes([QgsField("Name", QVariant.String), QgsField("Employees", QVariant.Int), QgsField("Revenue", QVariant.Double), QgsField("Rev. per employee", QVariant.Double), QgsField("Sum", QVariant.Double), QgsField("Fun", QVariant.Double)]) vl.updateFields() my_data = [ {'x': 0, 'y': 0, 'name': 'ABC', 'emp': 10, 'rev': 100.1}, {'x': 1, 'y': 1, 'name': 'DEF', 'emp': 2, 'rev': 50.5}, {'x': 5, 'y': 5, 'name': 'GHI', 'emp': 100, 'rev': 725.9}] for rec in my_data: f = QgsFeature() pt = QgsPointXY(rec['x'], rec['y']) f.setGeometry(QgsGeometry.fromPointXY(pt)) f.setAttributes([rec['name'], rec['emp'], rec['rev']]) pr.addFeature(f) vl.updateExtents() QgsProject.instance().addMapLayer(vl)
Open the attribute table and you’ll see that the last three fields are empty.
Let’s fill them with expressions!
The expression syntax is exactly the same as in the field calculator GUI. So you can test them in the GIU first, before copying them into your PyQGIS script.
The first expression computes the revenue per employee. The second one computes the sum of all revenue values in the layer. The final third expression doesn’t really make sense but illustrates the fact that we can use a wide range of expression functions, such as area and buffer in our expressions:
expression1 = QgsExpression('Revenue/Employees') expression2 = QgsExpression('sum(Revenue)') expression3 = QgsExpression('area(buffer($geometry,Employees))')
To execute our expressions, we need to provide an appropriate QgsExpressionContext. To set it up, use:
context = QgsExpressionContext() context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(vl))
(QgsExpressionContextUtils.globalProjectLayerScopes() is a convenience function that adds the global, project, and layer scopes all at once. Alternatively, those scopes can also be added manually. In any case, it is important to always go from “most generic” to “most specific” scope, i.e. from global to project to layer.)
Now we’re ready! We can loop through the layer features and apply the expressions by calling their evaluate() function:
with edit(vl): for f in vl.getFeatures(): context.setFeature(f) f['Rev. per employee'] = expression1.evaluate(context) f['Sum'] = expression2.evaluate(context) f['Fun'] = expression3.evaluate(context) vl.updateFeature(f)
However, this is not the only way to compute field values. Alternatively, you can also use pure Python, for example:
with edit(vl): for f in vl.getFeatures(): f['Rev. per employee'] = f['Revenue'] / f['Employees'] vl.updateFeature(f)
These are the basics of using QGIS expressions as well as pure Python to compute field values in PyQGIS. You can use both of these options depending on your preferences and specific requirements of your project.
PyQGIS 101 is a work in progress. I’d appreciate any feedback, particularly from beginners!
expression1 = QgsExpression(‘Revenue/Employees’)
expression2 = QgsExpression(‘sum(Revenue)’)
expression3 = QgsExpression(‘area(buffer($geometry,Employees))’)
The field’s names should not be inside double quotes?
Double quotes around field names are not necessary here.
what’s the “edit” in
with edit(vl):
for f in vl.getFeatures():
f[‘Rev. per employee’] = f[‘Revenue’] / f[‘Employees’]
vl.updateFeature(f)
?
with edit
is a shortcut that replaceslayer.beginEditCommand
andlayer.endEditCommand
as described in https://docs.qgis.org/3.4/en/docs/pyqgis_developer_cookbook/vector.html#modifying-vector-layers-with-an-editing-bufferSeems that for sizeable tables attribute editing can be very slow.
I would suggest calling from python the appropriate C++ processor. For example “Advanced Python field calculator”.