3

Using QGIS version: 3.28 LTR, in a layer with point geometry containing the field named "TYPE" and the attributes 'Normal' and 'Special', I am trying to develop an expression that allows me to label the calculation of the percentage of each different attribute in the collect centroid of each type. I show a screenshot with the expected result.

enter image description here

At the moment, I have partly managed to approach the solution using the following expressions in the label options, that can be seen in the second screenshot:

enter image description here

As you can see, for the moment with the following expression I manage to count the total number of only one attribute type, but I would like to substitute it by the percentage and add all attribute types:

CASE
WHEN "TYPE" = 'Special'
THEN 
count('Special',$geometry)
END

The Placement of the label I solve it with the following expression in the geometry generator:

convex_hull(collect($geometry,filter:="TYPE"='Special'))
2
  • which version of QGIS are you using?
    – Matt
    Commented Mar 17, 2023 at 10:50
  • QGIS version: 3.28 LTR
    – Acperience
    Commented Mar 17, 2023 at 10:56

1 Answer 1

10

It can be achieved by aggregating the various values into arrays (using filters to choose the attribute value), then finding the length of those arrays.

-- this case statement is to ensure the label is rendered only once per group (else it is rendered for every feature)
case when $id = array_min(array_agg($id, group_by:="TYPE"))
then
-- get total count
with_variable(
    'total',
    array_length(
        array_agg($id)
    ),
    
    -- count how many instances of "Normal"
    with_variable(
        'normal',
        array_length(
            array_agg(
                "TYPE",
                filter:="TYPE"='Normal'
            )
        ),
        -- count how many instances of "Special"
        with_variable(
            'special',
            array_length(
                array_agg(
                    "TYPE",
                    filter:="TYPE"='Special'
                )
            ),

             -- generate the label string based on the value of "TYPE" ( || is the concatenator operator, the @ symbol is to call the variables that were created above)
             case 
                when "TYPE" = 'Normal'
                then 'Normal: '  || @normal  || ' (' || to_string(@normal / @total * 100) || '%)'
                when "TYPE" = 'Special'
                then 'Special: ' || @special || ' (' || to_string(@special / @total * 100) || '%)'
             end
                
        )
    )
)
end

The adapted placement expression:

case 
    when "TYPE" = 'Special'
    then
        point_on_surface(
            convex_hull(collect($geometry,filter:="TYPE"='Special'))
        )
    when "TYPE" = 'Normal'
    then 
        point_on_surface(
            convex_hull(collect($geometry,filter:="TYPE"='Normal'))
        )
end

enter image description here

5
  • Thanks Matt. In relation to Placement, is it possible to differentiate the location for each type of attribute? That is, the point_on _surface is identified for each different attribute.
    – Acperience
    Commented Mar 17, 2023 at 11:38
  • 1
    It was a reasonably simple change. Just adding a case statement to both the label expression and the placement expression. You may need to experiment with the placement so that the the "Normal" label doesn't sit over the "Special" convex hull.
    – Matt
    Commented Mar 17, 2023 at 13:57
  • 1
    Sorry, I forgot to change the first line, the aggregation in the very first case statement needs a group_by parameter. I have added it to the answer.
    – Matt
    Commented Mar 17, 2023 at 14:11
  • Sorry. The effect I was looking for with the point_on_surface placement function is not quite convincing. Is it possible to group the labels a x,y position and delimit them with \n ?
    – Acperience
    Commented Mar 18, 2023 at 7:53
  • 1
    You could try your original placement expression, without the point_on_surface function. Or various other ways of placing them. If that doesn't work, you can look at the edit history of my answer to get the first expression that makes the label in one location :)
    – Matt
    Commented Mar 18, 2023 at 9:49

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.