1

I am selecting features based on whether "ZIP_CODE" value is found in an array. I am getting matches with the following:

layer = iface.activeLayer()

array = [93013, 35007]
matches = 0

for i in array:
    expression = ('ZIP_CODE = ' + str(i))
    request = QgsFeatureRequest().setFilterExpression(expression)
    for f in layer.getFeatures(request):
        matches += 1

print(matches)

Which works. How do I save this selection as a new Layer? If I have a JSON file I want to iterate over instead of this simple array, do I just load it in as per standard Pythonic way with:

with open(json_file) as json_data:
    data = json.load(json_data)
2
  • 2
    have a look to the class: QgsVectorFileWriter and the method writeAsVectorFormat where you can set the option onlySelected (bool = False) – write only selected features of layer -> qgis.org/pyqgis/master/core/…
    – eurojam
    Feb 15 at 9:44
  • Welcome to GIS SE. As a new user, please take the Tour, which emphasizes the importance of asking One question per Question. Please Edit this Question to focus on one question.
    – Vince
    Feb 15 at 12:39

3 Answers 3

3

I figured most of it out by changing the for loop to collect those selected features and save it to an in-memory layer as below:

for i in array:
    expression = ('ZIP_CODE = ' + str(i))
    selection = layer.getFeatures(QgsFeatureRequest().setFilterExpression(expression))
    layer.selectByIds([k.id() for k in selection],QgsVectorLayer.AddToSelection)

memory_layer = layer.materialize(QgsFeatureRequest().setFilterFids(layer.selectedFeatureIds()))

and then just saved that new in-memory layer out in the UI dashboard by right clicking on it. It is a one off so this worked for me

2

You can simplify your solution by doing away with the loop altogether.

layer = iface.activeLayer()

array = [35007, 93013]

# check ZIP_CODE against multiple values by using the `in` operator
# an `f string` is used to insert the array directly into the string
# the list is cast as a tuple so that the array is surrounded by parentheses () in the expression - instead of []
expression = f'ZIP_CODE in {tuple(array)}'

# can also use string concatenation as you have done
#expression = 'ZIP_CODE in ' + str(tuple(array)) 

req = QgsFeatureRequest()
req.setFilterExpression(expression)

# materialize the feature request directly, no need to select the features!
memory_layer = layer.materialize(req)
memory_layer.setName('filtered layer')   # name is same as `layer` by default so rename it

p = QgsProject.instance()
p.addMapLayer(memory_layer)
1

Extending great answers from @Matt, @OP himself, and also solutions mentioned in these threads: Creating temporary layer out of selection in QGIS and Duplicating layer in memory using PyQGIS. I would like to mention the native QGIS tool for dealing with selected features, i.e. "Extract selected features".

So, after selection, one could proceed with the following script:

# imports
import processing
from qgis.core import QgsProject

layer = QgsProject.instance().mapLayersByName("YOUR_LAYER_NAME")[0]

if layer.selectedFeatureCount() > 0:
    params = {'INPUT' : layer, 'OUTPUT' : 'D:/path/to/the/selection.gpkg' }
    processing.runAndLoadResults("native:saveselectedfeatures", params)

The above script should:

  1. Create a GeoPackage under this path D:/path/to/the/selection.gpkg
  2. Load this GeoPackage to your project

BTW, one can get a number of "matches" by means of the selectedFeatureCount() method of the QgsVectorLayer class.

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.