QGIS Spatial Statistics – Calculating Statistics of Points within Polygons of the Same Criterion

meanoverlapping-featurespoint-in-polygonqgisspatial statistics

In my QGIS 3.10 Project, I have one polygon layer and one point layer.

Each of these layers has objects that belong to different categories based on some attributes: for simplicity, let's say RED and GREEN polygons and RED and GREEN points. The point layer also has a numeric attribute.

I'm trying to calculate, for each polygon, the mean value of the numeric attribute of the points that are within it if they are both of the same types. That is if the polygon is RED use only the RED points within it and ignore the GREEN ones, and the opposite case is if the polygon is GREEN.

I've tried using "Join attributes by location (summary)" and “v.vect.stats` but I can't get the "same color rule" to work. Also tried creating a Virtual Layer but returns a lot of duplicated polygons.

Best Answer

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:

enter image description here

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:

  1. layer. This is the layer you are aggregating results from, the point layer, in my example, it's called 'point_layer'.
  2. aggregate. This is the type of aggregation you want to perform, for you it will be 'mean'
  3. 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.
  4. 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.).
  5. concatenator. Not needed.
  6. 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']
    )
Related Question