The primary source of data for a map that I'm making in QGIS 3.14 QGIS 3.20 is OSM.
There is a layer which contains natural peaks, obtained with a natural=peak query.
In order to reduce clutter, I'd like to only display a particular peak if it's the highest peak in a 5km radius. Is there a plugin that can help me achieve this, or some OSM query magic that would yield the same result?
(EDIT) What I've tried so far:
After suggestions from @Babel, I tried a couple of things.
I updated to QGIS 3.20.0-Odense and this is the version I'll be using from now on. This is the latest version available and contains functions such as overlay_nearest and array_max.
Since OSM data has the elevation data stored in the ele field as a string, I used the Field Calculator to create a new field called ele_int based on to_int(to_real(ele)) expression.
I had to first clean up and fix data fields that contained elevations such as 123m and 1`234 manually, as well as delete entries which didn't contain any elevation information in the ele field.
Then I tried using select by expression using the following:
array_max (
overlay_nearest(
@layer,
ele_int,
limit:=100,
max_distance:=1000
)
) > ele_int
But this results in 4122 peaks selected out of 4152 in total.
Interestingly, if I change max_distance to 10 or 50000, I still get 4122 selected rows, so max_distance doesn't affect the result.
(Hindsight: because there was a mismatch between the feature layer CRS and the project CRS, I had to use max_distance value of 0.08 in order to get the needed result)
One thing that does impact results is changing the limit in the expression, so if the limit is set to 1000, then 4149 peaks are selected, and if the limit is set to 10, then 3890 peaks are selected, but this doesn't give me the results that I need.
In the image below, you see the selection results. This tight group of 6 peaks is at least 14km away from the nearest peak outside of the group, so I'm using it to verify my results. The distance between the top left two peaks is approximately 2400 meters. It doesn't matter whether max_distance is set to 10, 1000, or 50000, I always see all 6 of these peaks selected. I've also verified that map unit is set to meters.
It feels like I'm very close to the goal but can't quite figure out the last bit. One thing I found interesting is that if I set the max_distance to 100000 (100 km), and the limit to 1, only one feature gets selected, and I would expect to see more. It feels almost like the expression is not performed for each feature, but only for one?
(EDIT 2) Additional findings about overlay_nearest
When I add a label to each peak for debugging so that every peak is labeled as to_string("ele_int") + ' - ' + array_to_string(overlay_nearest(@layer, "ele_int", limit:=5, max_distance:=100))
This is the result:
Note that overlay_nearest returns values while completely disregarding the distance to nearest point (the distance between each of these points is >2km). Also note that the first member of the array is the point itself, and the second point in the array is the closest one.
Either I'm using overlay_nearest wrong (more likely), or this could be a bug in QGIS (less likely).
(EDIT 3)
I start seeing the effects of max_distance when it's set to a very low value. In practice, I get results that I'd like to see when it's set to 0.07 (corresponds to around 5-10 km). Could it be the CRS I'm using (EPSG:32634)? The distance measurement tool gets the distance correctly though...
Final thoughts
The accepted answer works well. The problem I am seeing seems to be due to CRS mismatch between the feature layer and the project. It's possible even in this case to make things work by choosing a very small value for max_distance, something like 0.08.


array_max, you must have 3.18 or later. When I test it, the result changes with different values formax_distance. – Babel Jun 22 '21 at 10:31natural=peakquery. To that data, I apply the select by expression, and I do not usearray_maxbut instead thearray_lastandarray_sortsequence. I'm now going to check with 3.16 LTR. – Nebojsa Jun 22 '21 at 10:37elefor elevation. It is, however, formatted asstring(text), not as number, so that's why it doesn't work. You have to convert the values to a integer format first. You could do it directly in the expression, however I would recomand creating a new attributeelevationwith field calculator because you also have empty values that can create problems. I updated my answer accordingly. – Babel Jun 22 '21 at 12:30- I used the Field Calculator to add a field called ele_int, and I used the expression
- Then I tried selecting by
– Nebojsa Jun 22 '21 at 22:51to_int(to_real(ele))to populate itarray_maxofoverlay_nearestonele_intinstead ofeleand I still can't get it to work. I'll update my question with more details. Thank you for helping :)EPSG:4326, isn't it? You changed the project CRS, but not the layer CRS toEPSG:32634. That would explain why changing themax_distancehas no effect. Be sure to properly understand the difference between layer and project CRS, see: https://gis.stackexchange.com/a/392388/88814 – Babel Jun 23 '21 at 07:12