2

I wan't to filter features of a Shapefile layer from a user's selection with PyQGIS. When I select less than 30 features with a method like fid=1 or fid=2 or fid=3 ..., everything works fine but when I select over 30 features filter doesn't work and return me all the features of the layer. If I try a filter like fid >= 1 and fid <=150 (for example), it works. But it doesn't help for lists of unfollowing ids. I'm using QGIS 3.10.2.

Is there something wrong with this ? Does filters have size limits ? Is there a better way to filter features ?

# Layer
layer = iface.activeLayer()
features = layer.selectedFeatures()

# List ID of selected features
l = []
for feature in features:
    l.append(feature.id())
    
# Build arguments for the query
index = 0
query = []
prefix = 'fid='
while index < len(l)-1:
    query.append(prefix)
    query.append(l[index])
    query.append(' or ')
    index+=1
                
# Last element of the list
query.append(prefix)
query.append(l[index])
    
# Query
fullQuery = str(query).strip('[]').replace(',', '').replace("'", "")
    
# Filter
layer.setSubsetString(fullQuery)
4
  • Hi, there are a couple of things you could try - add a new field and populate the selected rows with a value that you then filter on. Or you could abandon the filter idea and create a new layer from your selection - as done here: gis.stackexchange.com/questions/80292/…
    – ian
    Nov 19, 2020 at 20:10
  • Indeed it's possible to add a new field and populate the selected rows, thanks for this suggestion.But I don't understand why the filter no longer works beyond a certain number of elements.
    – GeoGyro
    Nov 24, 2020 at 8:53
  • 1
    I don't think this will solve it, but in general, instead of fid = 1 or fid = 2 or... you should use fid in (1,2,...). It improves code readability. Dec 22, 2020 at 13:13
  • Thanks @GermánCarrillo, this syntax is more readable and more efficient. Features are well filtered, regardless the number of selected elements instead of my previous method. You should post il as an answer.
    – GeoGyro
    Dec 23, 2020 at 8:26

2 Answers 2

4

I don't know if this solves your question, but in general, instead of

fid = 1 or fid = 2 or...

you should use

fid in (1,2,...)

It improves code readability.

1

I am not sure what is wrong in your code but I have prepared a simple example that applies a filter based on features' id following the same logic of your example and it works fine with large number of features (e.g., 88 in this example). I am using QGIS 3.10.11:

# 1) Load a vector layer from natural earth database and import it to the project
gpkg_address = r"c:\%DATA_PAATH%\natural_earth_vector_50m_10m.gpkg"
lyr_name = "natural_earth_vector_50m_10m ne_10m_admin_0_countries"
lyr = QgsVectorLayer("{}|{}".format(gpkg_address, lyr_name), lyr_name, "ogr")
QgsProject.instance().addMapLayer(lyr)

# 2) Count the number of overall features, and select only the features with population over 10 millions
n_feat_tot = lyr.featureCount()
s_pop = "POP_EST"
lyr.selectByExpression('\"{}\" > {}'.format(s_pop, 10e6))
n_feat_sel = lyr.selectedFeatureCount()
print("Total features: {}, selected features: {}".format(n_feat_tot, n_feat_sel))
# Total features: 255, selected features: 88

# 3) Get the id of selected features. Remove the selection and then prepare the query. Finally, apply the query to the layer and count the remaining features. 
feat_id = lyr.selectedFeatureIds()
lyr.removeSelection()
query = [" or ".join(["fid={}".format(el) for el in feat_id])]
lyr.setSubsetString(query[0])
n_feat_subset = lyr.featureCount()
print("Subset features: {}".format(n_feat_subset))
# Subset features: 88

The input data are from Natural Earth database. I hope this helps.

5
  • Thanks for this answer. In my case the complexity of the filter is in the fact that the values ​​do not follow each other unlike this example which filters on values ​​greater than a defined threshold.
    – GeoGyro
    Nov 24, 2020 at 8:56
  • Hi GeoGyro, I am not sure if I understand the problem. In my example, the Ids of the selected features are not consecutive (a short excerpt of the feat_id list is given here: [102, 123, 122, 125, 127, 126, 113, 115, 114, 118, 137, ...] and the selection still works. Do you mean something different with "values do not follow each other"?
    – fastest
    Nov 24, 2020 at 18:02
  • Maybe I'm misunderstanding something in you're selection lyr.selectByExpression('\"{}\" > {}'.format(s_pop, 10e6)). In my case I'm making a selection with the graphic tool
    – GeoGyro
    Nov 25, 2020 at 7:53
  • An other big difference between our 2 methods : I use Shapefile while you use Geopackage.
    – GeoGyro
    Nov 25, 2020 at 8:14
  • Ok, I now understand that your selection is operated through the graphic_tool. However, the workflow you apply after the feature selection is exactly the same as the one shown in my code. Eventually, the difference between shapefile and geopackage can play a role. I can try to run the provided example with a shapefile as well to see what happens.
    – fastest
    Nov 25, 2020 at 16:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.