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.
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).
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.
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)
Any other ideas?
Similar questions I found: