13

I have a shapefile with only one field "DN". I would like to delete all features which does not have specific value of the field. Let's say the "DN" can be 1,2 or 3.

So far I was able to find out how to select Features and how to delete feature, but I did not succeed to combine them. Let's say I want only features with "DN" = 3 to remain:

Selection of the Features found here : Filter features based on their attributes using Python, however, I do not know if it does what it is supposed to do since I did not find the way how to check what is inside.

select = layer.getFeatures(QgsFeatureRequest().setFilterExpression(u'"DN"!=3'))

delete features found in the PyQGIS Developer Cookbook

res = Ilayer.dataProvider().deleteFeatures()

As far as I know, the deleteFeatures() requires "ID"s of the features, but I have no idea how to get them from from select which is QgsFeatureIterator.

Taras
  • 32,823
  • 4
  • 66
  • 137
MasterPJ
  • 359
  • 1
  • 3
  • 12

2 Answers2

27

You can loop over the iterator and get the id() for every feature in it:

with edit(layer):
    # build a request to filter the features based on an attribute
    request = QgsFeatureRequest().setFilterExpression('"DN" != 3')
# we don't need attributes or geometry, skip them to minimize overhead.
# these lines are not strictly required but improve performance
request.setSubsetOfAttributes([])
request.setFlags(QgsFeatureRequest.NoGeometry)

# loop over the features and delete
for f in layer.getFeatures(request):
    layer.deleteFeature(f.id())

or with QGIS < 2.12

request = QgsFeatureRequest().setFilterExpression('"DN" != 3')
request.setSubsetOfAttributes([])
request.setFlags(QgsFeatureRequest.NoGeometry)

ids = [f.id() for f in layer.getFeatures(request)]

layer.startEditing() for fid in ids: layer.deleteFeature(fid) layer.commitChanges()

Taras
  • 32,823
  • 4
  • 66
  • 137
Matthias Kuhn
  • 27,780
  • 3
  • 88
  • 129
  • Thank you, that was that! I just noticed that the FilterExpression was wrong (not u'"DN"=2||"DN"=1' but u'"DN"!=3' should be used). Please if you would edit your answer for this not to confuse other viewers. – MasterPJ Aug 29 '14 at 14:44
  • isn't it layer.dataProvider().deleteFeatures(ids)? – mbernasocchi Aug 13 '15 at 12:34
  • Using dataProvider() is possible but I prefer to work directly on the layer since this way the changes are communicated internally (to the map canvas, attribute table...) and other reasons. – Matthias Kuhn Aug 13 '15 at 21:34
  • 2
    layer.dataProvider().deleteFeatures(ids) has thrown crashes for me when layer.deleteFeature(fid) didnt... Bad crashes. The kind that cause a seg fault and kill qgis. The kind that take 6 hours to find... stick with the answer posted here. Bums me out because layer.dataProvider().deleteFeatures(ids) is all through my code and now I've got to fix it all. – Mr Purple Mar 09 '16 at 02:29
10

There is also a possibility of using the deleteSelectedFeatures() method from the QgsVectorLayer class for deleting selected features:

# choose an active layer
layer = iface.activeLayer()

make own selection

field_name = "DN" # specify your field field_values = (1,2,3) # specify values for features that you want to retain expression = f'"{field_name}" in {field_values}' layer.selectByExpression(expression)

delete selected features

if layer.selectedFeatureCount() > 0: layer.startEditing() layer.deleteSelectedFeatures() layer.commitChanges()

Taras
  • 32,823
  • 4
  • 66
  • 137