3

I would like to label groups of points (clusters) with only one label but several call-out lines. I built on top of the very appealing answer from @eurojam here: Giving one label to two points using QGIS

In order to make a distance aware grouping, I used the following code under the geometry-generator creating a point geometry (in contrast to the polygon geometry in the original post):

centroid(collect($geometry, group_by:="Label", filter:= distance(
        $geometry, geometry(@parent)) <=  @map_scale/50
        ))

Now I omit duplicated labels (if two points are clustered, only one label is needed). This allows to make us of the built in label displacement engine (i.e. to avoid labels overlapping each other or certain features). Probably, someone more savvy might include this within the geometry-generator. However, I implemented the following code for a data driven override for show label under rendering, basically adapting the solution here: https://gis.stackexchange.com/a/396489/203521

array_first(array_agg($id, group_by:="Label", filter:= distance(
        $geometry, geometry(@parent)) <=  @map_scale/50)) = $id  

This code displays a single label per group of points within a scale dependent radius. If several points are close, but not very close, it creates multiple centroids, but only one label. Despite that artifact, it seems to be working quite good.

Now, I struggle displaying the call-out lines. They connect to the centroid of the points, the generated geometry.

I tried to tweak the data-defined origin and target-section in the callout section under labeling. So I could provide a couple of x- and y-coordinates, but this does not seem to be working. Only one line is shown. enter image description here

I know can create a line symbology with the geometry generator. The following expression works for labels I moved manually:

make_line($geometry,
  make_point(array_first(array_agg(
         "auxiliary_storage_labeling_positionx",
         group_by:="Label", filter:= distance(
                 $geometry, geometry(@parent)) <=  @map_scale/50)
        ), 
        array_first(array_agg(
         "auxiliary_storage_labeling_positiony",
         group_by:="Label", filter:= distance(
                 $geometry, geometry(@parent)) <=  @map_scale/50)
        )))

However I don't have the auxiliary variables by default and I don't know how to populate those fields other than moving the labels with the custom placement tool. So this works for labels I moved, but not for the ones placed by default (the green one I moved, the red and violet one I didn't).

enter image description here

I could create an additional layer with a geometry generator that creates a line between the points and the clusters centroid, as shown below. But that's not exactly what I intended.

enter image description here

Another Idea is to create a virtual layer. Something along the following code could be used, but scale dependent clustering would be another issue then.

select "Label",st_collect(geometry) as geometry
from Singlepart
Group by "Label"

But the result is not exactly what I expected. One label per point (not per multipoint) and callout lines scale dependent to some selection features (as visible in the labels of group 1) enter image description here enter image description here

Any other ideas?

Similar questions I found:

2 Answers 2

1

Create a multi-point layer:

enter image description here

Then, in this order:

  1. define your label style,
  2. move the labels
  3. select Draw lines to all feature parts:

enter image description here

Result:

enter image description here

This is somewhat trick, as it seems not all multi-parts are handled correctly. In my example, initially the multi-points labeled "P" showed the correct multi-callout, the ones labeled "E" did not... A refresh helped.

1
  • 1
    Many thanks! I thought this might be a solution by creating a virtual layer and apply the labeling there. But I didn't succeed. I applied select "Label",st_collect(geometry) as geometry from Singlepart Group by "Label" but it creates a label per feature and not one per entry. The callout lines then are to some elements. "Label all elements of a multipart feature" is unchecked. I might add some edit.
    – Beni
    Commented Nov 21, 2023 at 8:51
0

I would like to add / "bump" this question. Originally I wanted to just add a comment under Beni's comment to the answer by RafDouglas C. Tommasi, but I don't have enough reputation. I would like to add this reply because there doesn't seem to be so many posts about this on GIS Stack Exchange, and not many concrete solutions for the ones that do, and so I think that maybe others in my position have been searching for a solution to this. I have also included things that I've tried not mentioned here. I thought it best to answer this question instead of making my own post. Please feel free to let me know if this is ok or not :)

I am also trying to solve the same problem, and I have looked at every question regarding it on this website, including the ones Beni links at the bottom of his question. I too cannot for the life of me, for the case of multiple sepearate objects / features (points or polygons) with the same attribute value**, achieve a single label which has multiple callout lines anchored to each of the objects / features. I feel very stupid!

Other things that I have tried not mentioned here:

  • Setting the value of fields auxiliary_storage_callouts_destinationx and auxiliary_storage_callouts_destinationy to be the same as the x and y coordinate of the feature itself by setting the expression $x and $y as the field values, and

  • Setting the value of the fields auxiliary_storage_callouts_originx and auxiliary_storage_callouts_originy to be the same as
    auxiliary_storage_labeling_positionx and
    auxiliary_storage_labeling_positiony respectively by setting the
    reference to those fields as the value of the fields.

In the hope that I could "force" QGIS to hold the same callout origin coords but use different callout destination coords, however this appears to have had no effect.

enter image description here

When I implement the code to hide duplicate labels (by adding a data override to the show label property in the rendering section of the layer label options:

array_first(array_agg($id, group_by:="Label", filter:= distance(
    $geometry, geometry(@parent)) <=  @map_scale/50)) = $id

This works, but also suppresses the callout lines.

To make matters worse, even when I add a geometry generator line component to the marker symbology of the point layer:

make_line($geometry,
  make_point(array_first(array_agg(
         "auxiliary_storage_labeling_positionx",
         group_by:="Label", filter:= distance(
                 $geometry, geometry(@parent)) <=  @map_scale/50)
        ), 
        array_first(array_agg(
         "auxiliary_storage_labeling_positiony",
         group_by:="Label", filter:= distance(
                 $geometry, geometry(@parent)) <=  @map_scale/50)
        )))

I can only get multiples lines to display if I use the simpler expression for the symbology geometry generator

make_line(
  make_point($x, $y),
  make_point( "auxiliary_storage_labeling_positionx" , "auxiliary_storage_labeling_positiony" )
)

But it is only with respect to the origin positions of their original (hidden) labels, not the visible label. Modifying the attribute table by altering the values of the fields mentioned above has no effect.

enter image description here

I am a civil engineer with around 8 years of experience with Autodesk software, mainly Civil 3D, so I've produced many a drawing / layout... hence why I feel very stupid right now for not being able to make this work!

Hope this is appropriate to post.

1
  • 1
    As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Commented Nov 1 at 13:53

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.