QGIS – How to Connect Points to Nearest Points with Similar Values

fields-attributeslinepointproximityqgis

I have a point shapefile and am trying to create lines connecting each point to the nearest other point with a similar value, based on one of its attributes. Specifically, the points are polygon centroids and each point has an attribute value for "area" corresponding to the area of the original polygon. I would like to connect each point to the nearest that is within a specified percentage of its own value. For example, if 50% was specified, a point with a value of 2 would connect to one with a value of 2.5 but not to one with a value of 4.

The "Nearest with Greater Value" plugin (https://plugins.qgis.org/plugins/qgis_nearest_greater/) does something similar but connects each point to the nearest greater one rather than the nearest of a similar value.

It's possible to do this manually by creating a new layer for each point containing only the other points within the specified range (e.g., for a 50% range and a point with a value of 2, all points with values between 1 and 3 would be exported to a new layer) and then running "Shortest line between features", but I need an automated method since my shapefile has thousands of points in it.

I am using QGIS 3.28.0.

Best Answer

You can use overlay_nearest() function that has an optional filter condition. The filter is a bit tricky, but you can use a variable @value based on the attribute value and than introduce it into the filter condition by concatenating it as a string and than convert it back to a function with eval().

Red arrowheads show the direction in whicht points are connected: 7 is linked to 5 and 5 to 7; 11 is linked to 7, too ("outgoing"), but 11 has no "incoming" connection: enter image description here

You can use the expression with Geometry Generator (for visualization) or Geometry by Expression (for actual lines) - see here for differences.

The expression looks like this: you can freely change the percentage in line 3. Be sure to introduce the name of your point layer in line 11:

with_variable(
    'percentage',
    50,  -- change this value
    make_line (
        $geometry,
        with_variable (
            'value',
            value,
            eval(
                'overlay_nearest (
                    ''points'',   -- change to the name of your points layer
                    $geometry,
                    limit:=11,
                    filter:="value">=' || (@value/100*(100-@percentage)) || ' and "value" <=' || ( @value * (100+@percentage)/100) || ')'
            )
        )[1]
    )
)