[GIS] Getting extent of composer map in PyQGIS

print-composerpyqgis

In answering a labeling question: Changing to alternate label if first label does not fit in QGIS? I found myself wondering if there was a way to programmatically get the extent of a composer map so it could be displayed in labels and used in expressions.

So the question arose: Is there a way to find the extent of a specific map on a specific composer programmatically in a way that could be used in the expression engine? I've come up with a solution (I'm posting as an answer below) But I'd be happy if there was a more efficient solution. If you have a better one let me know.

Best Answer

In order to use the result in an expression, a custom python expression is necessary. Here's the code I've come up with:

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

@qgsfunction(args='auto', group='Custom')
def getScale(composerName, mapName, feature, parent):
    # dictionary to store QgsComposerView.composition() items by name
    compDict = {}
    for comp in iface.activeComposers():
        # workaround to get name: read it from window title
        compDict[comp.composerWindow().windowTitle()] = comp.composition()
    mapScale = 0 # default to be returned if scale not found
    if composerName in compDict:
        mapItem = compDict[composerName].getComposerItemById(mapName)
        if mapItem:
            mapScale = mapItem.scale()
    return mapScale

The first challenge is getting a composer by name. Create a dictionary to hold the composers, then iterate over the activeComposers() list, storing them by name in the dictionary.

Next, if the composer name we're looking for is in the list, get the requested map and it's extent. Return either it or 0 to denote not found.

This works great with an atlas controlled map:

Scale shown for atlas item

In this case the expression used for the label is:

'scale' || getScale('Composer 1', 'Map 0')