3

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.

Select by expression results

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: enter image description here 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.

1 Answer 1

1

You can use QGIS expressions to check for each peak if it has another, higher peak within a radius of 5 km or not. Make a selection based on this and delete the peaks with at least one peak that is higher within a radius of 5 km.

You need QGIS 3.16 or later for the overlay_nearest function. From today, QGIS 3.20 is available for download, so I would recomand to get this version installed.

Let's suppose you have a point layer with the attribute hight (otherwise adapt the name in line 5 and the last line). Use select by expression with this expression:

array_last ( 
    array_sort(
        overlay_nearest( 
            @layer, 
            hight, 
            limit:=100, 
            max_distance:=5000
        )
    )
)> hight

If you use QGIS 3.18 or higher, you could replace the first two lines by array_max( and delete the last closing bracket ) in the second last line.

If you download peaks from OpenStreetMap, the field ele with elevation values comes formatted as string and some values are empty. Furthermore, there are integer values and decimal ones mixed. You could make the conversion directly in the expression above, but it could get confusing, so I advice first to create new field hight with field calculator with the following expression and than using this newly calculated field as input for the above expression:

if (ele ='',0,to_int(to_real(ele)))

Screenshot: Select by expression selects all points that have a higher peak within 5 km (yellow points) - delete them; the remaining points are the highest peaks within 5 km. For correct distance measurements, be sure to have your layer in an appropriate CRS:

enter image description here

12
  • 1
    Thank you, I wasn't aware of the "select by expression" feature, nor was I familiar with the scripting language. This answer worked for me.
    – Nebojsa
    Commented Jun 22, 2021 at 8:13
  • I do have a problem with this kind of query - it works the same regardless if I set max_distance to 1 or 100000. Changing the limit does work and give different results. The map unit is set to meters. @Babel do you have any idea why? I updated to QGIS 3.20 in the meantime.
    – Nebojsa
    Commented Jun 22, 2021 at 10:24
  • 1
    OK, so I guess best would be if you could provide your data (+ your project file, if possible). It's difficult to see what went wrong in your case using my own project and data - in my case, everything works fine. So there must be some setting, but from far, it's difficult to guess.
    – Babel
    Commented Jun 23, 2021 at 5:21
  • 2
    Your peak-layer from OpenStreetMap is probably still in EPSG:4326, isn't it? You changed the project CRS, but not the layer CRS to EPSG:32634. That would explain why changing the max_distance has no effect. Be sure to properly understand the difference between layer and project CRS, see: gis.stackexchange.com/a/392388/88814
    – Babel
    Commented Jun 23, 2021 at 7:12
  • 1
    You're welcome. Don't confuse distance tool on the map canvas and the distances used to calculate distances for each layer! Also don't confuse planimetric (cartesian) and ellipsoidal distances. That's why you get different distances.
    – Babel
    Commented Jun 23, 2021 at 15:54

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.