5

In QGIS 3.34.5, I am symbolising a large area of point features extracted from OpenStreetMap.

I currently have an ELSE clause that shows me the features that have not yet been symbolised in a large red dot.

enter image description here

However, I don't seem to be able to select and extract those features.

enter image description here

Is there a way I can select those features for extraction and further analysis?


I used the suggested answer from @J.R below (https://gis.stackexchange.com/a/483980/129409) of right-clicking on the symbol and selecting Select features, which I had completely missed!

However, there seem to be two problems:

  1. The symbolisation is scale-dependent, so the number of features that are selected depends on the zoom
  2. Even ignoring the scale, not all features with the large red are selected (see screenshot)

enter image description here

The latter issue may be a QGIS bug. The root cause appears to be due to the large number of NULL values in the fields being symbolised (being OSM data, most field values are NULL!). Here's a very simple QGIS example that shows that problem. Assume we have 6 points with various values in their x & y fields, in some cases NULL:

enter image description here

And the following symbolisation, including a similar ELSE clause:

enter image description here

As a result, features 1-3 are symbolised, but features 4-6 are not. However, using Select features on the ELSE category results in only feature 4 being selected! Features 5 & 6 have NULL values in fields x and y, and the filter that QGIS uses appears to be NOT (("x"='a') OR ("y"='b')) which is defeated by the NULLs

enter image description here

3 Answers 3

7

In the layer panel expend the symbology of your layer then right click on the red dot symbol. In the contextual menu there is the "Select Features" that will select all feature symbolized with a red dot or the "Show in attribute table" that will open the attribute table with the features symbolized by a red dot selected and filtered

3
  • Useful to know (I'd missed this!), but runs into a couple of problems in the case of my data/symbology. See edits in question. Commented Jul 20 at 0:25
  • 1
    @TomBrennan a quick fix could be to replace all null value with something like 'undefined' ...
    – J.R
    Commented Jul 20 at 9:53
  • Yes, that could be useful in certain circumstances. I found a couple of other slightly quicker fixes that work around the limitations so I've posted them as an answer too! Commented Jul 20 at 13:47
3

As mentioned in the edits to the question, there are a couple of issues with right-clicking on the symbol and selecting Select features - if your fields have NULL values, or your symbols are scale-dependent.

  1. If symbols are scale-dependent, the number of features that are selected depends on the zoom
  2. If fields have NULL values, the ELSE Select features logic uses NOT, both "x"='a' and NOT ("x"='a') are NULL if "x" is NULL ie the logic fails!

There are a couple of little tricks I found that might help others trying to work around this

No scale-dependent symbols

If you don't have any scale-dependent symbols, you can right-click on the ELSE symbol and click Show in Attribute Table. This will populate the Advanced Filter at the bottom with the auto-generated ELSE query, which doesn't work due to the NULLs. Eg:

NOT (
(("natural"='peak' or "natural"='spring')) 
OR (("natural"='water' or "natural"='saddle')) 
OR (("tourism"='camp_site')) 
OR (("tourism" in ('viewpoint','attraction'))) 
OR (("natural"='rock'))
)

Copy this out, remove the NOT, and paste into the Select Features by Expression box, and Apply. Then use the Invert Selection command, and you will now have the correct features selected!

Scale-dependent symbols

If you have scale-dependent symbolisations, but they are only max (or min), then you can use a similar approach to above. Eg your auto-generated filter will look something like:

NOT (
(("natural"='peak' or "natural"='spring') AND (@map_scale <= 100000)) 
OR (("natural"='water' or "natural"='saddle') AND (@map_scale <= 250000)) 
OR (("tourism"='camp_site') AND (@map_scale <= 500000)) 
OR (("tourism" in ('viewpoint','attraction')) AND (@map_scale <= 250000)) 
OR (("natural"='rock') AND (@map_scale <= 50000))
)

As before, copy this out, and remove the NOT. Then wrap the resulting expression in a with_variable function to create your own @map_scale variable that returns True to all @map_scale clauses. This is a bit of a hack, but currently works. Eg:

with_variable('map_scale',0,(
(("natural"='peak' or "natural"='spring') AND (@map_scale <= 100000)) 
OR (("natural"='water' or "natural"='saddle') AND (@map_scale <= 250000)) 
OR (("tourism"='camp_site') AND (@map_scale <= 500000)) 
OR (("tourism" in ('viewpoint','attraction')) AND (@map_scale <= 250000)) 
OR (("natural"='rock') AND (@map_scale <= 50000))
) 

Paste into the Select Features by Expression box, and Apply. Then use the Invert Selection command to get the correct features.

If you have a mix of max and min, you might need to manually (or Regex) remove the @map_scale sections in the expression as there will probably not be a value of @map_scale that will work.

1

You can use pyqgis to select all features that have a rule, then invert the selection:

layer = QgsProject.instance().mapLayersByName("points_554")[0] #Change points_554 to the name of your layer
rootrule = layer.renderer().rootRule()

#Create a list of all style rules
rules_list = []
for child in rootrule.children():
    rules_list.append(child.filter())

#print(rules_list) 
#[None, <QgsExpression: ' "objekttypnr"  =  1042 '>, 
# <QgsExpression: ' "objekttypnr"  =  2045 '>]

#For each rule that is not None, select by it by adding to current selection
for rule in rules_list:
    if rule is not None:
        print(rule)
        layer.selectByExpression(rule.dump(), QgsVectorLayer.AddToSelection)

#Invert the selection to select features without any rule
layer.invertSelection()

enter image description here

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.