2

Some time ago, I created a custom Python expression function to retrieve the boundaries of manually placed labels in QGIS:

from qgis.core import *
from qgis.gui import *
from qgis.utils import iface

@qgsfunction(args='auto', group='Custom', usesGeometry=False, referenced_columns=[])
def getLabelRect(x, y, feature, parent):
    # x,y ... coordinates of the manual label placement
    point=QgsPointXY(x,y)
    buffer=3
    rec=QgsRectangle.fromCenterAndSize(point,buffer,buffer)
    labels=iface.mapCanvas().labelingResults().labelsWithinRect(rec)
    if len(labels)>0:
        label_geom=labels[0].labelGeometry
        return label_geom
        
    return

My goal was to find a solution to another QGIS labeling question: Callout Labels with more lines

Unfortunately, the expression function only fetches the label boundaries within the main map window (iface.mapCanvas()). So my resulting question is: how can I retrieve label boundaries within a QGIS Layout map? ... or in more detail: can I get the map canvas of a Layout map item and use it like iface.mapCanvas()?

2 Answers 2

2

You can retrieve the label bounds of the map item in the layout like so:

p = QgsProject.instance()
manager = p.layoutManager()

# get reference to the example layout
layout = manager.layouts()[0]

# find the map item in example layout
map_item = [item for item in layout.items() if isinstance(item, QgsLayoutItemMap)][0]

label_results =  map_item.previewLabelingResults()

for label in label_results.allLabels():
    print(label.labelGeometry)

Result:

<QgsGeometry: Polygon ((4238472.78748475387692451 6207369.95093432907015085, 4239179.7527904137969017 6207369.95093432907015085, 4239179.7527904137969017 6208985.87163297925144434, 4238472.78748475387692451 6208985.87163297925144434, 4238472.78748475387692451 6207369.95093432907015085))>
<QgsGeometry: Polygon ((4231447.93659377843141556 6207504.37766740098595619, 4232154.90189943835139275 6207504.37766740098595619, 4232154.90189943835139275 6209120.29836605116724968, 4231447.93659377843141556 6209120.29836605116724968, 4231447.93659377843141556 6207504.37766740098595619))>

Note, this returns the corner coordinates of the (rotated) bounding box. It does not give the rendered geometry of a label background with a different shape (e.g. ellipse).

1
  • many thanks for the code example ... I must have overlooked previewLabelingResults(). With your help i can now revise my code.
    – christoph
    Commented May 11 at 15:02
2

With the help of @Matt I have revised my code example. Now it shows label boundaries in Layout maps as well, even if the labels are not shown in main map canvas. BTW: I'm using the context variables @layout_name and @map_id to retrieve the associated Layout maps.

from qgis.core import *
from qgis.gui import *
from qgis.utils import iface

@qgsfunction(args='auto', group='Custom', usesGeometry=False, referenced_columns=[])
def getLabelRect(x, y, feature, parent, context):
    mapItemId = context.variable('map_id')
    point=QgsPointXY(x,y)
    buffer=3
    rec=QgsRectangle.fromCenterAndSize(point,buffer,buffer)
    if mapItemId == 'canvas':
        labelResults=iface.mapCanvas().labelingResults()
    else:
        layoutName = context.variable('layout_name')
        map = QgsProject.instance().layoutManager().layoutByName(layoutName).itemById(mapItemId)
        labelResults = map.previewLabelingResults()
    
    labels = labelResults.labelsWithinRect(rec)
    if len(labels)>0:
        label_geom=labels[0].labelGeometry
        return label_geom
        
    return

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.