I'm trying to automate the creation of images using a combination of QGIS map documents and templates as discussed here using a standalone script. When complete, the script will regenerate a map using a new boundary set at run time, turning off layers that aren't used in a particular composer, and turning on the ones that are.
I'm able to generate images, adding various map elements (map items, legend, scale bar, etc.), but my test script isn't working when I need to change which layers are visible and adjust the extent accordingly. Everything seems to work except setting the visibility of the layer itself. Right now, only the layers that are checked whenever the qgis project is saved appear in the exported map. Based on the feedback here and here , I've tried adding a timer between each setVisible() call, but that still doesn't seem to work. I've also tried calling the setVisible() method inside a map and it works, it's only when it's run external from QGIS that it doesn't seem to affect layer visibility.
import sys
from qgis.core import (QgsProject, QgsComposition, QgsApplication,
QgsMapLayerRegistry)
from qgis.gui import QgsMapCanvas, QgsLayerTreeMapCanvasBridge
from PyQt4.QtCore import QFileInfo, QSize
from PyQt4.QtXml import QDomDocument
from PyQt4.QtGui import QImage, QPainter
import os
os.chdir("/home/project_name")
gui_flag = True
app = QgsApplication(sys.argv, True)
QgsApplication.setPrefixPath("/usr", True)
QgsApplication.initQgis()
project_path = 'report_maps.qgs'
template_path = 'location_overview.qpt'
canvas = QgsMapCanvas()
canvas.resize(QSize(1450, 850))
QgsProject.instance().read(QFileInfo(project_path))
root = QgsProject.instance().layerTreeRoot()
bridge = QgsLayerTreeMapCanvasBridge(root, canvas)
bridge.setCanvasLayers()
registry = QgsMapLayerRegistry.instance()
template_file = file(template_path)
template_content = template_file.read()
template_file.close()
document = QDomDocument()
document.setContent(template_content)
map_settings = canvas.mapSettings()
composition = QgsComposition(map_settings)
composition.loadFromTemplate(document)
#create list of all layers currently in the map
map_layers = [lyr for lyr in registry.mapLayers() if root.findLayer(lyr)]
#these layers are common for all maps
basemap = ["streets_labels", "streets_carto", "sca_parcels",
"boundary", "boundary_mask"]
#this section sets up an inset map that shows the project location
#in context of the region
inset_layers = ["boundary", "tiger_place_2016", "streets_carto_inset"]
# #this loop is to activate layers shown in inset map
inset_visible = []
for map_lyr in map_layers:
lyr = root.findLayer(map_lyr)
if lyr.layerName() in inset_layers:
inset_visible.append(map_lyr)
lyr.setVisible(2)
else:
lyr.setVisible(0)
all_cities = registry.mapLayersByName("tiger_place_2016")[0]
ids_all_cities = [f.id() for f in all_cities.getFeatures()]
canvas.zoomToFeatureIds(all_cities, ids_all_cities)
canvas.zoomScale(canvas.scale() * 1.2)
map_settings.setLayers(inset_visible)
inset_map = composition.getComposerItemById("inset_map")
inset_map.setMapCanvas(canvas)
inset_map.setNewExtent(canvas.extent())
#lock the inset layers style and extent to switch to larger map
inset_map.setLayerSet(inset_visible)
inset_map.setKeepLayerSet(True)
#this section sets up the thematic layers for this section which zooms
#in on the specific project boundary
visible_layers = []
for map_lyr in map_layers:
lyr = root.findLayer(map_lyr)
if lyr.layerName() in basemap + ["bldg_2014"]:
visible_layers.append(map_lyr)
lyr.setVisible(2)
else:
lyr.setVisible(0)
boundary = registry.mapLayersByName("boundary")[0]
ids = [f.id() for f in boundary.getFeatures()]
canvas.zoomToFeatureIds(boundary, ids)
canvas.zoomScale(canvas.scale() * 1.2)
map_settings.setLayers(visible_layers)
map_item = composition.getComposerItemById('main_map')
map_item.setMapCanvas(canvas)
map_item.setNewExtent(canvas.extent())
composition.refreshItems()
#set up the image for export
dpi = 300
dpmm = dpi / 25.4
width = int(dpmm * composition.paperWidth())
height = int(dpmm * composition.paperHeight())
image = QImage(QSize(width, height), QImage.Format_ARGB32)
image.setDotsPerMeterX(dpmm * 1000)
image.setDotsPerMeterY(dpmm * 1000)
image.fill(0)
imagePainter = QPainter(image)
composition.renderPage(imagePainter, 0)
imagePainter.end()
image.save("project_output.jpg", "jpg")
QgsProject.instance().clear()
QgsApplication.exitQgis()