He creado algunos PyQGIS funciones para configurar una impresión compositor, modificar el diseño (la adición de mapas, leyenda, título...) e imprimir el resultado como un archivo de imagen. Esto funciona bien con una o varias capas de vector - todos ellos se muestran en el archivo de imagen resultante.
Sin embargo, cuando trato de crear una impresión compositor de diseño que incluye una capa de Openlayers plugin, yo no conseguir el resultado esperado - la mayoría del tiempo la capa del mapa base que falta en todos y, a veces, algunos de los artefactos que se muestran.
El ejemplo de código siguiente debe ser inmediatamente ejecutable después de establecer el plotdir
parámetro en la parte superior para un deseado de la carpeta de salida. Es
- crea un nuevo proyecto de QGIS
- crea dos capas de vector en la memoria, cada uno con un punto de la geometría en algún lugar
- carga el OpenStreetMap mapa base de la OpenLayers plugin (haciendo clic en el QGIS menú Gui como no sé cómo cargar de otra manera)
- pasa las dos capas de la memoria y la Openlayers capa a un recién creado impresión compositor, establece algunos diseños cosas (la leyenda, título...) y guarda el resultado en un archivo de imagen.
Cuando ejecuto este, la leyenda muestra los tres deseado capas, pero el lienzo está en blanco (yo esperaría a ver, al menos, el mapa base como el punto de geometrías son bastante pequeñas). Alguna sugerencia de cómo correctamente incluir un mapa base en una impresión compositor con PyQGIS? Lo probé en Windows 7 con QGIS 2.4 y 2.6.
El código:
# imports
from qgis.core import *
from qgis.utils import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
plotdir = r'F:\\'
###################################
# function to start a new qgis project
###################################
def startNewProject():
print('starting new project')
iface.newProject(thePromptToSaveFlag = False)
return
###################################
# function to create a memory layer and add it to the map layer registry
###################################
def createMemoryLayer(layerType, layerName, x, y):
print 'create memory layer'
myMemoryLayer = QgsVectorLayer(layerType, layerName, "memory")
QgsMapLayerRegistry.instance().addMapLayer(myMemoryLayer, True)
feat = QgsFeature()
feat.setGeometry(QgsGeometry.fromPoint(QgsPoint(x,y)))
(res, outFeats) = myMemoryLayer.dataProvider().addFeatures( [ feat ] )
return myMemoryLayer
###################################
# function to load OpenLayers plugin layers and move it to the bottom of the layer tree
###################################
def loadOpenLayersPluginMap(mapProvider, openLayersMap):
print 'loading openlayers plugin layer'
webMenu = iface.webMenu() #get object of the Web menu of QGIS
for webMenuItem in webMenu.actions(): #open the Web menu of QGIS and loop through the list of web plugins
if 'OpenLayers plugin' in webMenuItem.text(): #look for OpenLayers plugin entry in the Web menu
openLayersMenu = webMenuItem #and open it
for openLayersMenuItem in openLayersMenu.menu().actions(): #open the OpenLayers plugin menu entry and loop through the list of map providers
if mapProvider in openLayersMenuItem.text(): #if the desired mapProvider is found
mapProviderMenu = openLayersMenuItem #open its menu entry
for map in mapProviderMenu.menu().actions(): #loop through the list of maps for the opened provider
if openLayersMap in map.text(): #if the desired map entry is found
map.trigger() #click the entry to load the map as a layer
# move the layer to the bottom of the TOC by putting all other layers above it (openlayers layer cannot be moved directly)
root = QgsProject.instance().layerTreeRoot()
for child in root.children():
if isinstance(child, QgsLayerTreeLayer):
childClone = child.clone()
root.insertChildNode(0, childClone)
root.removeChildNode(child)
return
###################################
# function to zoom to the extent of a layer
###################################
def zoomToLayerExtent(layer):
print 'zooming to layer '
# set the desired layer as active and zoom to it
iface.setActiveLayer(layer)
iface.zoomToActiveLayer()
return
###################################
# function to save a map layout as image file with map composer
###################################
def saveImagesWithPrintComposer(layers, extentLayer, plottitle, plotdir):
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()
layerSet = [layer.id() for layer in layers] # create a list of all layer IDs that shall be part of the composition
mapRenderer.setLayers(layerSet) # when using QgsMapRenderer, replace this with setLayerSet(layerset)
mapRectangle = extentLayer.extent() # set extent to the extent of the desired layer
mapRectangle.scale(2) # set scale as desired
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
#######
composition = QgsComposition(mapRenderer)
composition.setPlotStyle(QgsComposition.Print)
dpi = composition.printResolution()
dpmm = dpi / 25.4
width = int(dpmm * composition.paperWidth())
height = int(dpmm * composition.paperHeight())
#######
# add map to the composition
#######
x, y = 0, 0
w, h = composition.paperWidth(), composition.paperHeight()
composerMap = QgsComposerMap(composition, x, y, w, h)
composition.addItem(composerMap)
#######
# create title label
#######
composerLabel = QgsComposerLabel(composition)
composerLabel.setText(plottitle)
composerLabel.setFont(QFont("Arial",8))
composerLabel.adjustSizeToText()
composerLabel.setBackgroundEnabled(False)
composition.addItem(composerLabel)
composerLabel.setItemPosition(20,10)
#######
# create legend
#######
# create composer legend object
composerLegend = QgsComposerLegend(composition)
# set legend layers set (as the same as the map layerset)
composerLegend.model().setLayerSet(mapRenderer.layers()) #when using QgsMapRenderer, use layerSet() instead of layers()
# set titles
composerLegend.setTitle('')
newFont = QFont("Arial", 8)
composerLegend.setStyleFont(QgsComposerLegendStyle.Title, newFont)
composerLegend.setStyleFont(QgsComposerLegendStyle.Subgroup, newFont)
composerLegend.setStyleFont(QgsComposerLegendStyle.SymbolLabel, newFont)
# refresh legend
composerLegend.updateLegend()
# set feature count activated for all layers of the current map composition
composerLayerItem = QgsComposerLayerItem()
def activateFeatureCount(layer):
composerLayerItem.setLayerID(layer.id())
composerLayerItem.setShowFeatureCount(True)
return
[activateFeatureCount(layer) for layer in layers]
# set legend background
composerLegend.setBackgroundEnabled(False)
# set legend position
composerLegend.setItemPosition(20,20)
# add legend to composition
composition.addItem(composerLegend)
#######
# 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
#######
painter = QPainter(image)
sourceArea = QRectF(0, 0, composition.paperWidth(), composition.paperHeight())
targetArea = QRectF(0, 0, width, height)
composition.render(painter, targetArea, sourceArea)
painter.end()
#######
# Save composition to image file (other extensions possible)
#######
image.save(plotdir + plottitle + '.png', 'png')
return
###################################
# main function
###################################
def main():
# start a new qgis project
startNewProject()
# create memory layers
memoryLayer1 = createMemoryLayer('Linestring', 'MyFirstLayer', 2, 47) # some random coordinates
memoryLayer2 = createMemoryLayer('Linestring', 'MySecondLayer', 9, 48) # some random coordinates
# add openlayers plugin layer
loadOpenLayersPluginMap('OpenStreetMap', 'OpenStreetMap')
# zoom to first layer
zoomToLayerExtent(memoryLayer1)
# fetch all layers from the canvas
allLayers = QgsMapLayerRegistry.instance().mapLayers().values()
# save to file with print composer
saveImagesWithPrintComposer(allLayers, memoryLayer1, 'MyPlot', plotdir)
return
main()
print 'finished'