2

I want to export a map to PDF with PyQGIS. I do not need to add a legend or any additional information; I just want to export the extent visible to a PDF.

If I do this manually, I just go to Project --> Import/Export --> Export Map to PDF.

All programmatic explanations involve creating a special layout and exporting from there. There's probably a very simple way to do this, but I haven't found it yet.

Code below - the export piece (borrowed from the internet and slightly modified) is the only part that doesn't work, because I honestly don't know what to put for "layoutByName()." Is there a default layout? This probably has more to do with being new to QGIS than coding, but I'm stuck.

import qgis.utils
from qgis.utils import iface

#select features
temporaryCompaction = QgsProject.instance().mapLayersByName('Temporarycompaction')[0]
iface.setActiveLayer(temporaryCompaction)

iface.mapCanvas().setSelectionColor(QColor('red'))
expression = "to_date(Date) = to_date('2021-09-08', 'yyyy-MM-dd')"
temporaryCompaction.selectByExpression(expression)

#create layer from selected features and import to Layers
fn = r'U:\skelley\public\QGISstuff\PacTrustMergin-2test/newLayer.gpkg'
writer = QgsVectorFileWriter.writeAsVectorFormat(temporaryCompaction, fn, 'utf-8', driverName='GPKG', onlySelected=True)
selected_layer = iface.addVectorLayer(fn, '', 'ogr')
del(writer)

#copy styles from parent layer
copyLayer = QgsProject.instance().mapLayersByName('Temporarycompaction')[0]
iface.setActiveLayer(copyLayer)
iface.actionCopyLayerStyle().trigger()

#paste styles to new layer
pasteLayer = QgsProject.instance().mapLayersByName('newLayer')[0]
iface.setActiveLayer(pasteLayer)
iface.actionPasteLayerStyle().trigger()

#turn off Temporarycompaction layer
toggleOff = QgsProject.instance().mapLayersByName('Temporarycompaction')[0]
iface.setActiveLayer(toggleOff)
QgsProject.instance().layerTreeRoot().findLayer(toggleOff.id()).setItemVisibilityChecked(False)

#export to pdf
dailyReport = r'U:\skelley\public\QGISstuff\PacTrustMergin-2test\tempDailyReports\dailyReport1.pdf'
projectInstance = QgsProject.instance()
layoutmanager = projectInstance.layoutManager()
layout_item = layoutmanager.layoutByName(????)  
export = QgsLayoutExporter(layout_item)
export.exportToPDF(dailyReport, QgsLayoutExporter.PDFExportSettings())
1
  • You first need to create a layout. layout.setName("MyLayout") Then you add the layout to the layout manager inside your project. project.layoutManager().addLayout(layout) Then you need to add a map to your layout.... and then you edit the map features... and so on... Take a look at item 10.3 here: docs.qgis.org/3.16/pdf/en/… Commented Jan 4, 2023 at 22:03

1 Answer 1

2

To export the visible map extent to pdf you don't necessarily need a layout at all. You can instead use the QgsMapRendererCustomPainterJob class. It allows to render the map canvas to a custom painter. The painter can draw its contents to any image file or in combination with QPrinter print to pdf.

QPrinter has various methods to configure pdf output parameters such as page size, resolution, page orientation, margins, etc.. Take a look at the linked documentation for QPrinter

from qgis.PyQt.QtPrintSupport import QPrinter

settings = iface.mapCanvas().mapSettings()

printer = QPrinter(QPrinter.HighResolution)
printer.setOutputFileName(r'C:\your\path\to\export.pdf')
printer.setOutputFormat(QPrinter.PdfFormat)

# some optional settings to modify pdf output 
# I used some arbitrary values here, change it to your needs
printer.setPageOrientation(QPageLayout.Orientation.Portrait)
outputSize = settings.outputSize()
printer.setPaperSize(QSizeF(outputSize * 25.4 / settings.outputDpi()), QPrinter.Millimeter)
printer.setPageMargins(0, 0, 0, 0, QPrinter.Millimeter)
printer.setResolution(settings.outputDpi())
settings.setFlag(Qgis.MapSettingsFlag.ForceVectorOutput, True)

dest_painter = QPainter(printer)
dest_painter.setRenderHint(QPainter.Antialiasing)

render_job = QgsMapRendererCustomPainterJob(settings, dest_painter)
render_job.renderSynchronously()

dest_painter.end()

4
  • Hello and thank you for your response. I've run this several times: My original code creates a newLayer from selected features in a layer called "Temporarycompaction." If Temporarycompaction is checked when the code runs, that layer is printed to the PDF (despite the code unchecking it before the print process begins). If Temporarycompaction is not checked when the code runs, that layer is not printed to the PDF (and neither is newLayer). What I need: for the newLayer to be the only one of these two that is visible in the PDF.
    – Skel80
    Commented Jan 5, 2023 at 21:44
  • If I run it as a separate piece of code after my initial layer is created, it will export showing the newLayer as desired. How do I get this to work in one big piece of code, instead of piecemeal?
    – Skel80
    Commented Jan 6, 2023 at 0:28
  • 1
    @Skel80 I don't think I really understand what your issue is, but to specify that you only want to render specific layers to pdf you can use settings.setLayers(...). In your case probably settings.setLayers([pasteLayer]). This should then only export your newLayer.
    – CodeBard
    Commented Jan 6, 2023 at 8:33
  • Ty, this was exactly what I wanted to do (but wasn't articulating clearly), to determine which layers I wanted to appear in the PDF. Worked like a charm; many thanks.
    – Skel80
    Commented Jan 12, 2023 at 0:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.