8

I have a point layer with an attribute table like this:

id_point  class
       1      A
       2      B
       3      A
       4      C
       5      B
...

enter image description here

What I need is to count how many points of any class are in every polygon. Something like this

id_pol   A   B   C
  pol1   1   2   0
  pol2   1   0   1
...

Is there a way to count points within polygons grouping by a point attribute using Python in QGIS 3?

I think QGIS 2 had a Count Unique Features by Polygon but I can't find it in QGIS 3.

2
  • In QGIS 3, there is "Count points in polygon" tool which counts unique features with some settings. But your problem is different, and that tools doesn't help you. You should use a script. I've added a script that may help you. Commented May 20, 2020 at 23:02
  • Is there a way to make it work for lines instead of polygons ?
    – Cinouna
    Commented Feb 19, 2021 at 10:00

1 Answer 1

11

Use this script:

from PyQt5.QtCore import QVariant

# layers
polygon_lyr = QgsProject.instance().mapLayersByName("Polygons")[0]
point_lyr = QgsProject.instance().mapLayersByName("Points")[0]

# index number of "class" field 
field_index = point_lyr.fields().indexFromName('class')

# unique class names
unique_classes = point_lyr.uniqueValues(field_index)

polygon_lyr.startEditing()

# add a field for each class to polygon layer
for field_name in unique_classes:
    if polygon_lyr.fields().indexFromName(field_name)==-1:
        polygon_lyr.addAttribute(QgsField(field_name, QVariant.Int))

for feat in polygon_lyr.getFeatures():
    g = feat.geometry()
    req = QgsFeatureRequest(g.boundingBox()) # for performance
    classes = [p["class"] for p in point_lyr.getFeatures(req) if g.contains(p.geometry())]
    class_numbers_in_polygon = {cls: classes.count(cls) for cls in unique_classes}

    # add unique class numbers in polygon to the related field
    for cls in class_numbers_in_polygon:
        feat[cls] = class_numbers_in_polygon[cls]
        polygon_lyr.updateFeature(feat)

polygon_lyr.commitChanges()

enter image description here

3
  • Thanks Kadir Şahbaz, your script works fine, but when updating the fields I get an error: 'QgsVectorLayer' object has no attribute 'updatefields', although the new fields are added. I just save as another shp the original polygon layer before the first for instance as not to modify it, then I add the new shp with iface.addVectorLayer and define the layer by name. Commented May 21, 2020 at 11:16
  • Sorry, I've realized that you don't need updateFields in edit mode. I've deleted that line. (It would be updateFields, not updatefields) Commented May 21, 2020 at 11:36
  • Great, I made some changes to adapt it to my script and it worked fine. Thanks. Commented May 21, 2020 at 16:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.