In the previous section, we viewed vector layer fields and attributes. Now let’s use these attributes to put a filter on our layer so that it only contains certain features.

For example, this is how we can filter our countries vector layer to only features where the ADMIN value starts with an A:

vlayer.setSubsetString("ADMIN LIKE 'A%'")
for feature in vlayer.getFeatures():
    print(feature["ADMIN"])

This code is the equivalent of going to the layer properties and entering ADMIN LIKE ‘A%’ in the provider feature filter.

To remove the filter, we set an empty subset string:

vlayer.setSubsetString("")
for feature in vlayer.getFeatures():
    print(feature["ADMIN"])

To make our code more flexible, we can use a variable to define the character we want to filter for. The advantage of using a variable is that we only need to define it once and then we can use it in multiple places within our code. And if we eventually want to change it to a different character, we only have to change it in one place. The following code shows two different approaches for inserting a variable into a string:

my_char = "C"
vlayer.setSubsetString("ADMIN LIKE '"+my_char+"%'")
print("The following country names start with {}:".format(my_char))
for feature in vlayer.getFeatures():
    print(feature['ADMIN'])

The first approach is to concatenate strings using + operators. The second approach is called string formatting and the above syntax (with curly brackets) is specific to Python 3 (and thus requires QGIS 3).

String formatting looks complicated at first sight but it is also really powerful. For example, we can output the number of people living in each country using:

for feature in vlayer.getFeatures():
    print("{pop:.2f} mio people live in {name}".format(name=feature['ADMIN'],pop=feature['POP_EST']/1000000))


4.51 mio people live in Central African Republic
33.49 mio people live in Canada
16.60 mio people live in Chile
...

This is interesting for multiple reasons: first, the parameters in the format function can be provided in any order because we assigned them names (pop and name in this example). Second, we formatted the population value to display two digits after the decimal separator. For more string formatting examples see the official Python documentation.

This is one way to filter the features in a vector layer. You also saw some different methods for integrating variables into strings using either the + operator or string formatting.

Next


PyQGIS 101 is a work in progress. I’d appreciate any feedback, particularly from beginners!

24 comments
  1. Kurt said:

    my_char = “C”
    vlayer.setSubsetString(“ADMIN LIKE ‘”+my_char+”%'”)
    print(“The following country names start with {}:”.format(my_char))
    for feature in vlayer.getFeatures():
    print(feature[‘ADMIN’])

    why does replacing the first line of code from above with
    my_char = input(“Enter Char”)
    not work?

    • I assume input(“Enter Char”) is an attempt to make the script interactive but this is not the way to achieve interactivity in PyQGIS. I’ll definitely get into this topic later.

  2. Hi, I can’t differentiate the “two approaches” that you mention above. Can you please be more specific?

    Thanks, I’m learning a lot!

    • Approach #1 is string concatenation using + operators:
      "ADMIN LIKE '"+my_char+"%'"

      Approach #2 is string formatting:
      "ADMIN LIKE '{}%'".format(my_char)

  3. I hit my first major challenge here. I’ve never thought of using LIKE in the query builder. I don’t think I ever noticed its existence until this tutorial.

    So, I had to google it, the search led me to learning about wildcards.

    Also, the formatting was challenging but now I love it.

    Lastly, and this is a question, how do I tell qgis to perform a function on an already added layer instead of creating a new layer every time I update my code?

    Thanks ma’am for the benefits.

    • You can use vlayer=iface.activeLayer() to the currently active loaded layer.

  4. Luc said:

    Hello,
    According to the previous part of the tutorial and from what I’ve understood, I suggest to replace (in the project already containing ne_10m_admin_0_countrie
    the “vlayer = iface.addVectorLayer(path, “countries”, “ogr”)”
    by “vlayer=iface.activeLayer()”

  5. Hello, Thanks for the tutorial I am a beginner,

    I try string formatting, but I have this error

    UnicodeEncodeError: ‘ascii’ codec can’t encode character u’\xe9′ in position 10: ordinal not in range(128).

    Please help me. Thanks

    • sniperleonidas said:

      I try to put # -*- coding: utf-8 -*- as first line of the script but its does’nt work.

  6. Claudia said:

    Hi, I could not find ‘SetSubsetString’ option through the list. I am working with QGIS 2.18, How can I solve this problem?

    • These tutorials require QGIS3. The PyQGIS API has changed.

  7. Paweł Swoboda said:

    Hi thank you for your blog, it’s very helpful. Unfortunately QGIS Filter still has an unsolved bug – LIKE operator is not case-sensitive.
    For example:

    vlayer.setSubsetString(“FIELD_NAME LIKE ‘%Wola'”)

    returns features where the FIELD_NAME values ends with ‘wola’, e.g. Tywola, Suchowola etc.
    Is it possible to run setSubsetString function using re.match or regexp_match or anything similar?

  8. Laura said:

    Hi,

    Thank you very much for this tutorial!
    I have a question about the print function. Why do you use 2 quotes at one time and 1 at other times:

    vlayer.setSubsetString("")
    for feature in vlayer.getFeatures():
        print(feature["ADMIN"])
    
    my_char = "C"
    vlayer.setSubsetString("ADMIN LIKE '"+my_char+"%'")
    print("The following country names start with {}:".format(my_char))
    for feature in vlayer.getFeatures():
        print(feature['ADMIN'])
    
    • Hi Laura. In Python, single and double quotes can be used interchangeably. There is no difference between print(feature["ADMIN"]) and print(feature['ADMIN']).

  9. Laura said:

    And another question;

    I want to use as much variabele as posible(sorry its Dutch):

    vbo="//asp.local/gt-home$/lbaten_gt/My Documents/_GEO informatie/GEO_werkmap/Projecten/Dalfsen/BIZ/output/VBO_binnen_BIZ.shp"
    veld_gebrdoel="gebruiksdo"
    gebr_doel="woonruimte"
    
    vlayer=iface.addVectorLayer(vbo, "BAG", "ogr")
    #iface.showAttributeTable(vlayer)
    #for field in vlayer.fields():
    #    print(field.name())
    vlayer.setSubsetString("veld_gebrdoel LIKE 'industrie%'")
    for feature in vlayer.getFeatures():
       print(feature["veld_gebrdoel"])
    
    
    Error:
    
    Traceback (most recent call last):
      File "C:\PROGRA~1\QGIS3~1.8\apps\Python37\lib\code.py", line 90, in runcode
        exec(code, self.locals)
      File "", line 1, in 
      File "", line 10, in 
    KeyError: 'gebr_doel'
    

    Last line, rename the variable: veld_gebrdoel into the fieldname “gebruiksdo” goes well, but it isn’t a variabele anymore. and I have to edit this line everytime:

    vbo="//asp.local/gt-home$/lbaten_gt/My Documents/_GEO informatie/GEO_werkmap/Projecten/Dalfsen/BIZ/output/VBO_binnen_BIZ.shp"
    veld_gebrdoel="gebruiksdo"
    gebr_doel="woonruimte"
    vlayer=iface.addVectorLayer(vbo, "BAG", "ogr")
    #iface.showAttributeTable(vlayer)
    #for field in vlayer.fields():
    #    print(field.name())
    vlayer.setSubsetString("veld_gebrdoel LIKE 'industrie%'")
    for feature in vlayer.getFeatures():
       print(feature["gebruiksdo"])
    

    How can I use a variabele in the printfeature line?

      • Laura said:

        That make sense. Thank you!

  10. beans said:

    how much of an expression can this method handle? Any other suggestions to accomplish the same task with a different route? The length of the expression was around 47,000 characters.

    2020-06-12T10:57:22 CRITICAL Layer MUPOLYGON : OGR[3] error 1: SQL Expression Parsing Error: memory exhausted. Occurred around :
    ‘77231’,’77242′,’77245′,’77249′,’77251′,’77253′,’77282′,’76207′,’76221′,’76229′,

  11. I can’t get the code to work with field names with spacing in for example ‘field_name’ works but “field name” doesn’t.

  12. Alexandre said:

    Hello !
    I discovered that : vlayer.setSubsetString(“ADMIN” LIKE ‘A%’) doesn’t work for me,
    but vlayer.setSubsetString(‘ADMIN LIKE \’A%\’ ‘) does.
    Also vlayer.setSubsetString(‘ “ADMIN” LIKE \’A%\’ ‘) does work too.
    Can you explain why there is this different behaviour between your qgis and mine please ?

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.