# Counting points in each polygon so that points do not repeat QGIS

I have a points layer and a polygon layer. I need to count points in each polygon/buffer so that points do not repeat. For instance, here is an example with 4 polygons and 8 points inside in total.

What I get from ArcGIS Summarize Within, as well as from QGIS Count Points in Polygon is that:

1. polygon consist of 2 points;
2. polygon - 4 points;
3. polygon - 2 points;
4. polygon - 2 points.

However, the count of 1. and 2. polygon is incorrect because results show 6 points in total even though there are only 4, as you can see in the picture. The result should look something like this:

1. polygon consist of 2 points;
2. polygon - 2 points;
3. polygon - 2 points;
4. polygon - 2 points, so that points do not overlap in several polygons.

If I had only a few polygons, this would be quite easy, but as I have several polygons and points, manual work is not a real solution.

I'm pretty sure that this could be done very easily with some expression, however, I could not figure it out.

• For the two points in common with polygon 1 and polygon 2, how to know if it belongs to polygon 1 or polygon 2 ? Commented Mar 23, 2021 at 12:56
• In this case, it doesn't really matter, the result could also be: 0 points in 1. polygon and 4 points in 2. polygon, as long as the count is correct. The problem is that each function that I used counts more points, as described above. Commented Mar 23, 2021 at 13:01
• I erased the `pyqgis` tag, because no code was demonstrated Commented Mar 23, 2021 at 13:54
• Understand the "tech" requirement but do not see when it could be useful. Any pointer for a practical use case? Commented Mar 26, 2021 at 22:04

With a simple SQL query, you can get what you want. Under QGIS, Database menu > DB Manager > Virtual Layers :

``````WITH poly_pts AS (
SELECT
MIN(polygons.id) AS poly_id,
points.id AS pt_id
FROM polygons, points
WHERE ST_WITHIN(points.geometry, polygons.geometry)
GROUP BY points.id
)

SELECT poly_pts.poly_id, COUNT(*) AS pts_count
FROM poly_pts
GROUP BY poly_pts.poly_id
``````
• You need two layers named `polygons` and `points`, each must have an `id` field unique
• `poly_pts` selects the lowest `polygons` ID that contains each `points` feature
• The second query just count the number of points for each `polygons` ID.

It gives :

poly_id pts_count
1 2
2 2
3 2
4 2
• That is what I thought about, Virtual Layers =) I was almost there and you posted an answer Commented Mar 23, 2021 at 13:49

For QGIS 3.16+ you can use the `overlay_nearest` expression to achieve this. The idea is to find for each point the nearest centroid of any of the polygons and assign thus each point to one polygon. Than you can use count the numbers of points assigned to the same polygon (see screenshot below).

In the following expression, change the values of `polygon`, `points` and `id` to the layer and field names you use:

1. On the point layer, use the field calculator to create a field `in_polygon` with this expression: `array_first ( overlay_nearest( 'polygon', id))` (= small black labels in the screenshot)

2. On the polygon layer, create a new field counting the no. of points belonging to it:

``````with_variable (
'id',
\$id,
aggregate(
'points',
'count',
in_polygon,
filter:= in_polygon=  @id
)
)
``````

Screenshot: each point (white) is connected (for visualization purpose only) to the nearest polygon-centroid - thus "assigning" each point to one (and only one) polygon. Based on this, for each polygon count only the points "attached" to itself:

Edit: Reaction to @J. Monticolo's comment

If you have points outside the polygon, the solution need another addition: you don't want to count points that are outside the polygon. In this case, in step one, replace the expression from above with this one here (step 2 remains the same):

``````if (
within(
\$geometry,
buffer (
aggregate(
'polygon',
'collect',
\$geometry
),
0
)
),
array_first (
overlay_nearest(
'polygon',
id
)
),
NULL
)
``````

See the result: points outside the polygons are not assigned to any polygon and thus they are not counted:

• And if there are points outside polygons ? Commented Mar 26, 2021 at 18:06
• You're right, see improved answer Commented Mar 26, 2021 at 21:16
• Much better solution but not simpler expression ! Commented Mar 26, 2021 at 21:30
• Indeed, but that's the price for a better solution. Another option would be first to use `select by expression` to select only those points that are inside a polygon: for this selection than the first, simpler, version of the solution works. Commented Mar 26, 2021 at 21:33