Creating raster based on function of distance to points and assorted attributes in QGIS

In QGIS 3.30 I have a dataset of points associated with several values, call them integers A and B.

I want to create a raster with maybe 5km x 5km pixels where the value associated with each pixel indicates a function of A, B and the distance to all points within a specific maximum distance.

Something of pseudo-code:

For each pixel in the raster.

• For each point within about 300km of the centre of the pixel calculate a value based on distance, A and B
• Sum all these calculations and assign them to the value of the raster

The final goal will be to combine a few of these rasters in numerous ways in the usual ways, such as clipping to a polygon and applying a function to combine these function raster values.

2 Answers

First create a vector polygon grid with the size/resolution of the raster pixels you want to create. Then use the following expression to create a new attribute field to create the value you need, based on fields `a` and `b` from layer `points` (in line 4, change the kind of calcluation to adapt to your use case):

``````array_sum (
overlay_nearest (
'name_of_point_layer',  -- change layer name
a / b,  -- the calculation you want to make, based on fields "a" and "b" from layer points
max_distance:=300000, -- max. distance of point to take into consideration
limit:=-1
)
)
``````

When finished, run Menu Raster > Conversion > Rasterize (Vector to Raster) and set the new field creted before as input for `Field to use for a burn-in value`.

Edit

To answer your follow up question from the comments: to include the the distance between the feature being evaluated and the item from the array returned by overlay_nearest so that the calculation changes based on that distance, use the following expression. It calculates the division of attributes a and b and multiplies this with the distance a point is away from the current feature (thus higher values for points far away):

``````array_foreach(
overlay_nearest (
'points', -- replace with the name of your point layer
@feature, -- available since QGIS 3.28
max_distance:= 300000,  -- define the distance
limit:= -1
),
attribute (@element, 'a') /  -- get the value for attribute field a
attribute (@element, 'b') *  -- get the value for attribute field a
length (make_line (\$geometry, geometry(@element))  -- get the distance between the feature being evaluated and the item from the array returned by overlay_nearest
)
)
``````
• Thanks, this is exactly what I was looking for! A follow up question though. Is there any way to incorporate the distance between the cell being evaluated and the items from the array returned by overlay_nearest? So that my calculation can change based on that distance. I know that there are distance functions, but I am not sure in this context which feature "geometry" would refer to, and what I could use for the other point. May 23 at 5:47
• See updated answer May 23 at 7:24
• Just wondering why you used "length(make_line(\$geometry, geometry(@element)))" rather than "distance(\$geometry, geometry(@element))"? Is one faster to execute than the other? May 23 at 15:53
• Simply seems I overlooked the `distance()` function... ;-) May 23 at 15:59

So I thought that I would post the solution that I came up with based on the excellent guidance of @Babel.

My source dataset was a spreadsheet of geocoded EV chargers across the country that came in as strings. So my first step was to create binned fields as follows:

``````-- handle definition
try(coalesce(to_int(attribute( @feature, 'Number of')), 0), 0)

-- handle_bin definition
case
when attribute( @feature, 'handles') > 10 then 5
when attribute( @feature, 'handles') >= 8 then 4
when attribute( @feature, 'handles') >= 4 then 3
when attribute( @feature, 'handles') >= 2 then 2
when attribute( @feature, 'handles') >= 1 then 1
else 0
end

-- power definition
try(coalesce(to_int(attribute( @feature, 'Power Ra_1')), 0), 0)

-- power_bin definition
case
when attribute( @feature, 'power') >= 250 then 5
when attribute( @feature, 'power') >= 150 then 4
when attribute( @feature, 'power') >= 100 then 3
when attribute( @feature, 'power') >= 50 then 2
when attribute( @feature, 'power') >= 1 then 1
else 0
end
``````

After this, it was a pretty simple matter to follow Babel's instructions to create a grid (I used 10km for speed since my country is very large, might increase resolution later but it does not change anything in the code) and then add a calculated field as folllows

``````-- DCTravelScore definition
coalesce(
array_sum(
array_foreach(
overlay_nearest (
'Australia_chargers_xlsx_2c8dfa1c_99e3_4eeb_ae67_988ade0ad84e',
@feature, -- available since QGIS 3.28
max_distance:= 100000,  -- define the distance
limit:= -1
),
with_variable(
'distance',
distance(\$geometry, geometry(@element)),
coalesce(attribute (@element, 'handle_bin'), 0) *
coalesce(attribute (@element, 'power_bin'), 0) *
case
when @distance <= 5000.0 then 5
when @distance <= 10000.0 then 4
when @distance <= 20000.0 then 3
when @distance <= 50000.0 then 2
when @distance <= 100000.0 then 1
else 0
end
)
)
), 0
)
``````

Not sure whether there is a more elegant way to do binning like this? At least the `with_variable` function exists to create a variable in local scope without jumping into full script mode!