Great question. Welcome to the weird and wonderful world of the aggregate()
function. It's very powerful but tricky to learn, I've used it a lot and still have to read the documentation carefully most times I use it.
Add a new field to your polygon layer and populate it using the aggregate()
function:

For this, it's useful to remember that the layer you are running this expression on is called the parent layer.
Let's run through the parameters:
- layer. This is the layer you are aggregating results from, the point layer, in my example, it's called 'point_layer'.
- aggregate. This is the type of aggregation you want to perform, for you it will be 'mean'
- expression. This is the expression you are aggregating (sorry not sure how else to explain it). In your case, it's simply your number field, "num_field" in my example.
- filter. This is how you are going to filter your results, otherwise, it would just return the mean for all points. You need to filter the points in two ways, the first filter being that they are intersected by the parent polygon, and the second filter being that their colour field ("point_colour_field" in my e.g.) matches the parent polygon's colour field ("poly_colour_field" in my e.g.).
- concatenator. Not needed.
- order_by. Not needed.
First filter: to check they intersect you use the intersects()
function, this requires two input geometries. The first is the point geometry which is just $geometry
, and the second is the geometry of the parent polygon which is called using geometry(@parent)
.
Second filter: The "point_colour_field" needs to equal the parent polygon "poly_colour_field". The polygon colour field is called using attributes(@parent)['poly_colour_field']
The filters are combined using and
.
With all that said, this is the expression to use (with your own layer and field names substituted in of course):
aggregate(
'point_layer',
'mean',
"num_field",
intersects($geometry, geometry(@parent))
and "point_colour_field" = attributes(@parent)['poly_colour_field']
)