qgis / QGIS

QGIS is a free, open source, cross platform (lin/win/mac) geographical information system (GIS)
https://qgis.org
GNU General Public License v2.0
10.47k stars 2.99k forks source link

QGIS expression overlay: filter based on other layers #43146

Open Babelgit opened 3 years ago

Babelgit commented 3 years ago

The very handy overlay functions to QGIS expressions introduced in version 3.16 have an optional filter argument. However, it seems that it works only for the layer that is refered to - the help says:

an optional expression to filter the target features to check

It would be nice if this filter condition could be used to write filter conditions based on other layers that are refered to e.g. using expressions that allow referring other layers like get_feature_by_id (). Right now, this does not seem to be possible. See here for a use case: https://gis.stackexchange.com/questions/391120/qgis-expression-with-overlay-fuction-filter-condition-based-on-comparison-of-at

DelazJ commented 3 years ago

I can't check right now (and may have quickly read the SE discussion) but should this not be possible using the @parent variable? Might be some examples of it's usage in the docs or other functions (eg, aggregates)

Babelgit commented 3 years ago

With @parent, you can't refer to another layer, as far as I can see. The filter condition allows only to filter inside the refered layer. At least, I don't know how the syntax would be to be able to compare values from two layers for the filter condition.

DelazJ commented 3 years ago

Mind testing something like filter:="id2" <> attribute(@parent, 'id1')?

Babelgit commented 3 years ago

Tested it with no success, see screenshots with and without the filter. Result should look like screenshot 1, but without the lines connecting blue point 1 to red point 1, blue 2 to red 2 etc.: just points whereid1<>id2 should be connected: blue points 17 and 19 to red point 1, blue 15 to red 2 etc.

See here for screenshots and the project + layers: https://drive.switch.ch/index.php/s/af5cHue6P3NA9xM

DelazJ commented 3 years ago

I think I get your expected result with (filter out the identical ID after we get the array of results)

collect_geometries(
    array_foreach(
        array_filter(
            overlay_nearest( 
                'layer2',
                "id2"
            ), 
            "id1"<> @element
        ),      
        make_line ( $geometry,
                    geometry( get_feature( 'layer2', 'id2', @element ) )
        )
    )
)

Back to the feature request, I think the purpose of the filter parameter is to reduce the dataset (layer2) to use for research, so it's applied before it proceeds to any overlay test; that new set of features is used for all the checks hence should somehow be the same. So not sure if it would have worked in your case (id1 changes every time), but there indeed might be case where you want to filter consistently the dataset using another layer. maybe should be done previously using a variable to store it? But I may be misinterpreting. @olivierdalang ?

Babelgit commented 3 years ago

Yes, your expression does exactly what I wanted to do. The explanation that the filter condition is mainly there to limit the number of features to evaluate (and thus reduce processing time) makes sense. Apart from that, it still would be nice if it would be implemented.

agiudiceandrea commented 2 years ago

@Babelgit please see https://github.com/qgis/QGIS/pull/45744 Such PR makes it possible (since QGIS 3.22.1 and 3.23.0) to use a simple workaround that allows to write a filter string also referring to a source layer (or any other layer) field like: eval('overlay_nearest( \'target_layer\', $currentfeature, filter:=field_target_layer=' || "field_source_layer" || ')')

So, for your project:

make_line (
    eval( 'overlay_nearest( \'layer2\', $geometry, filter:=id2<>' || "id1" || ' )' )[0],
    $geometry
)

image