I have written a function in Python / PyQGIS (no standalone application, so copy/paste it to the Python console editor to run it) that takes a VectorLayer as argument, creates a MapRenderer object for that layer, then creates a MapComposer object using the MapRenderer, adds the map, a title and a legend to the composition and saves it as a png file.
Everything works fine except for the fact that the legend always includes all layers that are currently visible in the QGIS layer widget. What I like to have is to show only the layer in the legend that I passed to the MapRenderer (and then to the composition). See the following example.
That's what the QGIS layer widget looks like: Two layers are loaded, one is selected.
That is what the output image looks like when running the script below: Both layers from the layer widget are included in the legend instead of only the first layer (which is the only one visible in the plot).
This is my script. When trying to run it yourself, set the plotdir
parameter at the top of it to match your desired output directory. The script does not load any layers, so this has to be done in advance.
from PyQt4.QtCore import *
from PyQt4.QtGui import *
plotdir = r'C:\pyqgis_plots\\'
def saveImagesWithMapComposer(layer):
print 'saving images with map composer'
#######
# set up layer set, extent and create a map renderer
#######
mapRenderer = QgsMapSettings() #new in QGIS 2.4 - replaces QgsMapRenderer()
#mapRenderer = QgsMapRenderer()
layerset = [layer.id()]
mapRenderer.setLayers(layerset) #when using QgsMapRenderer, replace this with setLayerSet(layerset)
mapRectangle = mapRenderer.fullExtent()
mapRenderer.setExtent(mapRectangle)
mapRenderer.setOutputSize(QSize(1600,1200)) #when using QgsMapRenderer(), setOutputSize needs a second argument 'int dpi'
#######
# create a composition and pass the renderer
#######
comp = QgsComposition(mapRenderer)
comp.setPlotStyle(QgsComposition.Print)
dpi = comp.printResolution()
dpmm = dpi / 25.4
width = int(dpmm * comp.paperWidth())
height = int(dpmm * comp.paperHeight())
#######
# add map to the composition
#######
x, y = 0, 0
w, h = comp.paperWidth(), comp.paperHeight()
composerMap = QgsComposerMap(comp, x, y, w, h)
comp.addItem(composerMap)
#######
# create label
#######
composerLabel = QgsComposerLabel(comp)
composerLabel.setText(layer.name())
composerLabel.adjustSizeToText()
comp.addItem(composerLabel)
composerLabel.setItemPosition(20,10)
#######
# create legend
#######
composerLegend = QgsComposerLegend(comp)
composerLegend.model().setLayerSet(mapRenderer.layers()) #when using QgsMapRenderer, use layerSet() instead of layers()
composerLegend.setTitle('')
comp.addItem(composerLegend)
composerLegend.setItemPosition(20,20)
#######
# create image and initialize
#######
image = QImage(QSize(width, height), QImage.Format_ARGB32)
image.setDotsPerMeterX(dpmm * 1000)
image.setDotsPerMeterY(dpmm * 1000)
image.fill(0)
#######
# Render composition
#######
imagePainter = QPainter(image)
sourceArea = QRectF(0, 0, comp.paperWidth(), comp.paperHeight())
targetArea = QRectF(0, 0, width, height)
comp.render(imagePainter, targetArea, sourceArea)
imagePainter.end()
# Save image to disk (other extensions possible)
image.save(plotdir + layer.name() + '.png', 'png')
return
###################################
# call function
###################################
# get first layer from the canvas and pass it to the plot function
layers = iface.legendInterface().layers()
layer = layers[0]
saveImagesWithMapComposer(layer)
print 'finished'
I already tried using the deprecated QgsMapRenderer class instead of QgsMapSettings (see inline comments what has to be changed to try this) but the result is the same.
Any suggestions what I am missing here?
QgsComposerLegend.model()
is deprecated in favor ofQgsComposerLegend.modelV2()
, see the API docs. Maybe this is the new way to go? However, I could not manage yet to make it work this way...2.4
and above see: gis.stackexchange.com/a/223127/36886