Exporting Print Layouts from Processing Scripts

When trying to automate your GIS workflows, one important step is the production of maps. Creating and exporting maps in QGIS is done via the Print Layout. One can automate creation of maps via the a rich Python API using the QgsLayout class.

See our post Rendering Print Layouts from QGIS Models for a no-code solution to exporting print layouts.

It is recommended to use the Processing Framework for writing python scripts in QGIS. Here I will show you how to write a processing script that takes a saved map template and renders the current project as a PDF file.

For this example, I am assuming a simple map template with 2 items

  • A label item for the title named ‘Label 1’
  • A map item named ‘Map 1’

To use this layout as a template, we should first use Layout → Save as Template... This will save the layout configuration as a .qpt file.

Next open the Processing Toolbox and go to Scripts → Create New Script…

In the Script Editor, copy/paste the following code.

from PyQt5.QtCore import QCoreApplication
from qgis.core import (QgsProject, QgsLayout, QgsLayoutExporter, 
    QgsReadWriteContext, QgsMapSettings, QgsProcessingAlgorithm, 
    QgsProcessingParameterFileDestination, QgsProcessingParameterFile,
    QgsProcessingParameterString)
from PyQt5.QtXml import QDomDocument


class ExportLayoutAlgorithm(QgsProcessingAlgorithm):
    """Exports the current map view to PDF"""
    TEMPLATE = 'TEMPLATE'
    OUTPUT = 'OUTPUT'
    TITLE = 'TITLE'
    
    def flags(self):
          return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

    def initAlgorithm(self, config=None):
        self.addParameter(
            QgsProcessingParameterFile(
                self.TEMPLATE,
                self.tr('Template File'),
            )
        )
        
        self.addParameter(
            QgsProcessingParameterString(
                self.TITLE,
                self.tr('Map Title'),
                'My Map'
            )
        )
        
        # We add a file output of type CSV.
        self.addParameter(
            QgsProcessingParameterFileDestination(
                self.OUTPUT,
                self.tr('Output File'),
                'PDF File (*.pdf)',
            )
        )

    def processAlgorithm(self, parameters, context, feedback):
        template = self.parameterAsFile(parameters, 'TEMPLATE', context)
        title = self.parameterAsString(parameters, 'TITLE', context)
        pdf = self.parameterAsFileOutput(parameters, 'OUTPUT', context)
        # Load template from file
        project = context.project()
        layout = QgsLayout(project)
        layout.initializeDefaults()
        with open(template) as f:
            template_content = f.read()
        doc = QDomDocument()
        doc.setContent(template_content)
        # adding to existing items
        items, ok = layout.loadFromTemplate(doc, QgsReadWriteContext(), False)
        title_item = layout.itemById('Label 1')
        title_item.setText(title)
        exporter = QgsLayoutExporter(layout)
        exporter.exportToPdf(
             pdf, QgsLayoutExporter.PdfExportSettings())
        return {'OUTPUT': pdf}

    def name(self):
        return 'export_layout_pdf'

    def displayName(self):
        return self.tr('Export Layout As PDF')

    def group(self):
        return self.tr(self.groupId())

    def groupId(self):
        return ''

    def tr(self, string):
        return QCoreApplication.translate('Processing', string)

    def createInstance(self):
        return ExportLayoutAlgorithm()

Save the script and close the Script Editor. You will see the script appear as a new algorithm under Scripts → Export Layout as PDF

Double-click to open it. Choose the saved .qpt file as the Template File. Enter a map title of your choice and choose an output file. Click Run.

The current project will be rendered in the Map element of the template and a PDF file will be created.

Another advantage of writing our export algorithm as a processing script is that it can be used as part of a model and create maps without human input. So if you have a workflow where you need to get source data, process, analyze and produce a map – you can use scripts such as this to create a model and run it without having to click any buttons.

10 Comments

Leave a Comment

  1. Hello, I did run the process but I get the error below, I attached the template file (.qpt) and the script, I appreciate the help.

    regards

    Eddison

    https://www.dropbox.com/sh/f9pfflntsorxhxl/AAC5BPy9uxPg1qLpBPwEGRf-a?dl=0

    Procesando algoritmo…
    Algoritmo ‘Export Layout As PDF’ comenzando…
    Parámetros de entrada:
    { ‘OUTPUT’ : ‘C:/BORRAR/MAPA.pdf’, ‘TEMPLATE’ : ‘C:\\HACER_MAPA\\plantilla.qpt’, ‘TITLE’ : ‘MAPA BORRADOR’ }

    Traceback (most recent call last):
    File “C:\Users\Usuario\AppData\Roaming\QGIS\QGIS3\profiles\default\processing\scripts\IMPRIMIR_LAYOUT_PDF.py”, line 58, in processAlgorithm
    title_item.setText(title)
    AttributeError: ‘NoneType’ object has no attribute ‘setText’

    La ejecución falló después de 0.48 segundos

  2. Great into to the subject, but if you want a portrait layout set clearExisting to True in loadFromTemplate().

  3. Super cool! Thanks! I want to automate the printing/providing layout in qgis. It was a great luck that I could find your script! But I have some questions:
    1. I need to add some more input variables from the use, like name, version and …! I followed same as Title prepration and etc. It shows all the required fied now when I run the script. But I get always an error that the title_item = layout.itemById(‘Label 1’)
    title_item.setText(title) is empty!
    2. How can I implement this script for Atlas? I am so new in these part of QGIS and programming with pyqgis (I have quite good experience with python but not pyqgis)

Leave a Reply