Exploring The QGIS Expression Engine, Part 4: Selecting By Attributes And Location With One Expression
I recently encountered a Facebook post asking whether any GIS software can select by both attributes and location with one tool. My answer:
Yeah, wanna guess which software?
To which the person answered, knowing me, "QGIS with python🐍?", to which I clarified, you don't need python for that and referred them to my second post about the expression engine: Exploring The QGIS Expression Engine, Part 2: What's Missing From Select By Location, in it I perform both a spatial selection based on an attribute selection inside one expression (I select all the countries intersecting a 3 degree buffer from the Netherlands). Now that was a relatively complex expression since it used a reference geometry from within the same layer.
An expression using a features geometry can be used just as easily as using the attributes from its table. For example, using the same Natural Earth Countries layer, if you would want to select a country by name or continent your expression would look like this:
"NAME" = 'Angola' or "CONTINENT" = 'Europe'
But what if you want to select using the geometry of a country?
We can use either the geometry itself, and interpolate it to get a specific node, the centroid, the X/Y coordinate or a derived attribute like length for lines or area for polygons. Lets use a derived attribute and select all countries larger than 1,000,000 square kilometers.
($area/1000000) > 1000000
Looks pretty simple, diving by 1,000,000 to get square kilometers and selecting using that number.
Now lets try something a bit more complex. lets interpolate geometry, and check which countries have a centroid which is west of the prime meridian. now lets break this process down to how we do that.
1. get the geometry of each feature: $geometry -> returns geometry
2. get the centroid of the geometry: centroid($geometry)
-> returns geometry
3. get the X coordinate of the centroid: x(centroid($geometry)) -> returns number
So any x coordinate west of the prime meridian would be smaller than 0 since x coordinates increase going east and decrease going west of the prime meridian. our final expression looks like this:
x(centroid($geometry)) < 0
See how simple that was? if we wanted to use the geometry of a specific feature from another layer we could use a function like get_feature which takes three parameters, layer, attribute and value which allows you to select a feature by the value of one of its attributes.
When we have a feature from another layer instead of the geometry of our layer we can use the geometry(feature) function instead of the $geometry attribute. you can also use that on the same layer to use a specific feature.
Lets use all of this to get all the European countries that touch (share a border) with Russia and have a population larger than 10,000,000
1. first we get the feature for Russia: get_feature('Countries_50m','NAME','Russia') -> returns a feature
2. now extract the geometry of that feature: geometry(get_feature('Countries_50m','NAME','Russia')) -> returns a geometry
3. now lets check who touches that geometry: touches(geometry(get_feature('Countries_50m','NAME','Russia')),$geometry) -> returns true\false as 1 or 0
4. now we just add the attribute selection for continent: touches(geometry(get_feature('Countries_50m','NAME','Russia')),$geometry) and "CONTINENT" = 'Europe'
This return true or false for each country, when true that country would
be added to the selection so out of the 14 countries that touch Russia,
only 8 are counted as European.
5. and finally we select only those countries with a population larger than 10,000,00: touches(geometry(get_feature('Countries_50m','NAME','Russia')),$geometry) and "CONTINENT" = 'Europe' and "POP_EST" > 10000000
We are now only left with Ukraine and Poland, using one spatial condition and 2 attribute table conditions.
And that's it, all you have to do is break down your expression so using multiple functions in a row don't look as intimidating and you can get results very quickly selecting by both attribute and location.
previous posts about the expression engine:
Exploring The QGIS Expression Engine, Part 1: Getting Values From JSON & HSTORE
Exploring The QGIS Expression Engine, Part 2: What's Missing From Select By Location
Exploring The QGIS Expression Engine, Part 3: Writing Custom Expression Functions
Comments
Post a Comment