4

I am trying to accomplish what should be a simple task: selecting features using an expression in the python console. I am using QGIS 2.18.14 and the Alaska Airports dataset from the QGIS sample data. I want to select the feature with the highest value in the “ELEV” field. My code snippet is:

layer = iface.activeLayer()
expr = QgsExpression('"ELEV" = maximum"ELEV"')
selection = layer.getFeatures(QgsFeatureRequest(expr))
ids = [s.id() for s in selection]
layer.setSelectedFeatures(ids)

However, the result is that no features are selected (with no error messages).

If I use this expression : "ELEV" = maximum( "ELEV" ) in the Select by expression dialog from the GUI, all works as expected, selecting the feature with the maximum elevation value.

Using other expressions in the python console also work successfully, for example:

layer = iface.activeLayer()
expr = QgsExpression('"ELEV" <100')
selection = layer.getFeatures(QgsFeatureRequest(expr))
ids = [s.id() for s in selection]
layer.setSelectedFeatures(ids)

The above code snippet works well, selecting all features with elevation values less than 100.

As I am very much a beginner with Python, I am assuming the problem is with the syntax of the expression within my python code. To this end I have tried typing the expression in different ways including:

expr = QgsExpression('"ELEV" = maximum"ELEV"')

expr = QgsExpression('"ELEV" = maximum\"ELEV\"')

expr = QgsExpression('"ELEV" = maximum\( "ELEV" \)')

expr = QgsExpression('"ELEV" = maximum\("ELEV"\)')

Which all give the same result- no error message but no features selected.

How do I use the ‘maximum’ aggregates function as an expression with PyQGIS code?

3 Answers 3

3

Not sure if it's a bug or something else but a possible workaround could be to determine the maximum value using the QgsVectorLayer::maximumValue() method and putting this into the QgsExpression:

layer = iface.activeLayer()
field_name = 'ELEV'
field = layer.fieldNameIndex(field_name)
max_value = str(layer.maximumValue(field))
expr = QgsExpression(field_name + ' = ' + max_value)
selection = layer.getFeatures(QgsFeatureRequest(expr))
ids = [s.id() for s in selection]
layer.setSelectedFeatures(ids)
2
  • 1
    Thanks @Joseph. As usual, your solution worked perfectly!
    – Ben W
    Commented Dec 22, 2017 at 1:18
  • @BenW - Most welcome, glad it helped! Although it would still be interesting to know why your original expression did not work in the first place. Perhaps the aggregate functions haven't been exposed fully to be valid for QgsFeatureRequest...
    – Joseph
    Commented Dec 22, 2017 at 11:12
2

For QGIS 3.x there is a solution, that utilizes the QgsVectorLayerUtils() class and selectByIds() method:

So, your code may looks as:

layer = iface.activeLayer()
field_name = "id"

values = QgsVectorLayerUtils.getValues(layer, field_name)[0]
values_no_dupl = list(set(values))
max_value = max(values_no_dupl)

expression = QgsExpression(f"{field_name}={max_value}")

selection = layer.getFeatures(QgsFeatureRequest(expression))
ids = [s.id() for s in selection]
layer.selectByIds(ids)

result

Selection also can be achieved via the selectByExpression() method:

layer = iface.activeLayer()
field_name = "id"

values = QgsVectorLayerUtils.getValues(layer, field_name)[0]
values_no_dupl = list(set(values))
max_value = max(values_no_dupl )

layer.selectByExpression(f"{field_name}={max_value}")

References:

1

Stumbled over this question years later, having the same problem, and found the reason for our problem using aggregate functions in QgsFeatureRequest. Its the "scope", in which the request is evaluated. It seems to be automatically applied when called from Qgis-Query-Editor, but is missing if running the same expression from console.

layer = iface.activeLayer()

context = QgsExpressionContext()
context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(layer))

request = QgsFeatureRequest()
request.setFilterExpression('"ELEV" = maximum("ELEV")')
request.setExpressionContext(context)

selection = layer.getFeatures(request)
ids = [s.id() for s in selection]
layer.select(ids)

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.