2

I've gone through many posts here that describe some ways of selecting features by attribute, but there is really no definitive answers as to which way is the fastest way of selecting features from a QgsVectorLayer by attribute values. Here is the case in point, I have a python list of attribute values, such as ['obj1', 'obj2', 'obj3'], these are the values of object 'name', which is also an attribute in the QgsVectoryLayer, say, layer. I need to select these map features on the map as fast as I can as the layer usually has hundreds of thousands of features. Here is a few ways I tried:

method 1:

name_list = ['obj1', 'obj2', 'obj3']
feature_ids = [f.id() for f in layer.getFeatures() if f.attributes()[0] in name_list]
layer.setSelectedFeatures(feature_ids)

method 2:

feature_ids = []
for n in name_list:
   for feature in layer.getFeatures(QgsFeatureRequest(QgsExpression('"name"=' + "'" + n + "'"))):
      feature_ids.append(feature.id())
layer.setSelectedFeatures(feature_ids)

neither of the above is fast, when executed over a few large layers, it is really slow. So, what would be the fastest way to select features on map fast by attribute values.

To time it: one can put the above methods into functions, then do the following to time it:

import timeit
print "method1: %s seconds " % timeit.timeit(method1,number=1)
print "method2: %s seconds " % timeit.timeit(method2,number=1)

The QGis Core library is from QGIS 2.12.3 Lyon; GDAL/OGR 1.11.3; GEOS 3.5.0-CAPI-1.9.0

  • 1
    For performance testing I think you should always include some timing code - otherwise "really slow" depends on your perspective. – PolyGeo Jun 29 '17 at 21:56
  • ok, I added some code for timing it in the OP. – For Comment Jun 29 '17 at 22:17
  • I think that code should be merged into your two code snippets and the results of running each presented. – PolyGeo Jun 29 '17 at 22:30
  • Did the answer help you solve the problem? – Germán Carrillo Jul 25 '17 at 16:33
3

I suggest you to follow recommendations given in How to optimize QgsFeatureRequest with filter expression. If your data is on a database, create an index for the name field.

Finally, give this code snippet a try, it has additional optimizations for your case:

expr = "\"name\" IN ('{}')".format( "','".join( name_list ) )
req = QgsFeatureRequest().setFlags( QgsFeatureRequest.NoGeometry )
req.setSubsetOfAttributes( [] ).setFilterExpression( expr ) 

it = layer.getFeatures( req )
layer.setSelectedFeatures( [f.id() for f in it] )
|improve this answer|||||

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.