I'm trying to represent in every single atlas feature the basin for several streams. Each basin can have one or more stations. The data to plot is a point vector, with columns for "data" and "LABEL" for each station where the data belongs to.

For statistical purposes, I've created an HTML label to count,for each atlas feature, the points with data for each station that are within each represented basin. I've followed the answer: How to display attributes of features intersecting the Atlas feature in a Print Composer label? , using the function proposed by she_weeds:

aggregate('LAYER_NAME','concatenate_unique',"ATTRIBUTE",intersects($geometry,@atlas_geometry), ',', "ATTRIBUTE")

It works, but due to the 'concatenate_unique' operator, when two stations have the same number of collected data (0 for example), only one value appears on the HTML label.

F.e.: Nº of points with valid data for basin X for each one of its stations: 21,0,66. But i know that this basin have 4 stations, so the answer should be: Nº of points with valid data for basin X for each one of its stations: 21,0,0,66.

  • Would it help to use 'concatenate' instead of 'concatenate_unique'?
    – she_weeds
    Oct 10, 2023 at 6:07
  • That only shows each attribute value for each intersecting feature separated by commas...imaging 66 values showed that way when I only want that value: 66 for 1 station. Or 66,25 for 2 stations. Oct 10, 2023 at 9:01
  • I think maybe you need to aggregate the stations by ID separately from the actual count of valid data? I'm not entirely clear how your station data is structured, if you could share a sample of your data and fields and the exact expression you used (i.e. which fields did you aggregate using), that would make it easier to help.
    – she_weeds
    Oct 10, 2023 at 9:21
  • sorry, I'm newbie, how can i share a file with you in a private way? Oct 10, 2023 at 10:12
  • Are you able to take a screenshot and just blank out the relevant sections or show dummy data instead? There's unfortunately no easy way to share files privately on GIS.SE. The actual data itself is not that important, just the structure and what you're trying to achieve. For example do you have basin layer, station layer, and station data layer. Or do you just have station data layer with station ID field and you have been grouping by that.
    – she_weeds
    Oct 10, 2023 at 10:21

1 Answer 1


After discussion it appears the question is about aggregating data on another layer that is within an atlas feature, grouped by another field. As the data is on another layer it has to be aggregate either using aggregate() or one of the overlay_ functions, but there is no access to a further data field to group the results by, only filter.

The OP's workaround was to use those functions to aggregate an aggregate (i.e. instead of overlay_intersects('data_points',"data_field"), use overlay_intersects('data_points',count("data_field",group_by:="aggregate_field")) - the inner aggregate function, count() in this instance, lets you nominate a field to group by. But you still get a result for each feature that is within the atlas feature.

So for example if within your first atlas feature you have 3 points in station A, 2 points in station B, and 3 points in station C, the result is [3, 3, 3, 2, 2, 3, 3, 3] . Applying array_distinct() or similar to that yields [3, 2] when the desired result is [3, 2, 3].

One specific solution to that is to add the aggregate field back in to differentiate the first set of 3 from the second set of 3, by concatenating it to the inner aggregate to get for example [A3, A3, A3, B2, B2, C3, C3, C3]. Then apply array_distinct() or similar to get [A3, B2, C3] and go from there.

Example data:

enter image description here

Use the following expression - you can add an optional extra filter parameter after "station_id" in the count() function, the example below has "data_field" > 20

array_to_string(array_distinct(overlay_contains('data_points',"station_id"||': '||count("data_field","station_id"))),', ')


enter image description here

The more elegant approach would probably be to use attribute tables where suitable though, as shown above - use the count() expression as an attribute.

  • 1
    Hurray! Eureka! You did it! It works just the way i've been searching for! I think my fault was to focuss on try to count points, instead of grouping it on a first step. Thank you very much! Oct 11, 2023 at 10:42

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.