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.

Next


PyQGIS 101 is a work in progress. I’d appreciate any feedback, particularly from beginners!

Advertisement
9 comments
  1. MARCELO said:

    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.

      • Katja said:

        I don’t know whether it’s a version difference or how the columns are defined, but my code did not work unless I used double quotes for the column names.

        Great course otherwise! 🙂

  2. Sebastian said:

    what’s the “edit” in

    with edit(vl):
    for f in vl.getFeatures():
    f[‘Rev. per employee’] = f[‘Revenue’] / f[‘Employees’]
    vl.updateFeature(f)

    ?

  3. Vla Dunev said:

    Seems 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”.

  4. Hannes said:

    Thank you Anita! It is so cool way how one can mix expressions and Python code.

    For self-written Python expression functions (https://docs.qgis.org/3.22/en/docs/user_manual/expressions/expression.html) it looks really terse and to the point, as one can get the context as magical last parameter:

    from qgis.core import *
    from qgis.gui import *

    @qgsfunction(args=’auto’, group=’Custom’, usesgeometry=True)
    def expression_via_python(feature, parent, context):
    expression = QgsExpression(‘area($geometry)’)
    value = expression.evaluate(context)
    return value

  5. Ludwig said:

    Hello Anita, this course is excelent and very usefull, thank you very much.
    I had the ambition to extend the “pure python”-code-part, so…

    total_sum = vl.aggregate(QgsAggregateCalculator.Sum, “Revenue”)[0]

    with edit(vl):
    for f in vl.getFeatures():
    f[‘Rev. per employee’] = f[‘Revenue’] / f[‘Employees’]
    f[‘Sum’] = total_sum
    f[‘Fun’] = f.geometry().buffer(f[‘Employees’],8).area()
    vl.updateFeature(f)

    I’m so proud… :-)

  6. Bernhard said:

    Hi Anita, I wonder if there is a possibility to set all values in one go using expressions without iterating over the features. Like in QGIS’ field calculator. I would appreciate if you could share any information on this.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: