3

I'm using python to command the print composer and export images/pdf (https://opensourceoptions.com/blog/pyqgis-create-and-print-a-map-layout-with-python/)

I'm looping through layers by name to export each layer. It works quite well for all but it's messy if layers are next to each other as I want to only show one. I need and want to use the themes that I've set up but I can't find a way to bring them to Print Composer.

I can change the theme using iface.mapCanvas().setTheme('green'), but this doesn't affect the layout in the Print Composer.

How can I use a different theme for each layouts via Python? Can it be done through QgsMapThemeCollection and applyTheme()?

from qgis.PyQt import QtGui

layernames = [layer.name() for layer in QgsProject.instance().mapLayers().values()]

for each in layernames: 

    layers = QgsProject.instance().mapLayersByName(each)
    print(layers)
    layer = layers[0]
    project = QgsProject.instance()
    manager = project.layoutManager()
    layoutName = each + "_layout"
    iface.mapCanvas().setTheme(each)

    layouts_list = manager.printLayouts()
    #remove any duplicate layouts
    for layout in layouts_list:
        if layout.name() == layoutName:
            manager.removeLayout(layout)

    layout = QgsPrintLayout(project)
    layout.initializeDefaults()
    layout.setName(layoutName)
    manager.addLayout(layout)

    #create map item in the layout
    map = QgsLayoutItemMap(layout)
    map.setRect(20, 20, 20, 20)

    #set the map extent
    ms = QgsMapSettings()
    ms.setLayers([layer])  #set layers to be mapped
    rect = QgsRectangle(ms.fullExtent())
    rect.scale(1.6)
    ms.setExtent(rect)

    map.setExtent(rect)
    map.setBackgroundColor(QColor(255, 255, 255, 0))

    layout.addLayoutItem(map)

    map.attemptMove(QgsLayoutPoint(5, 20, QgsUnitTypes.LayoutMillimeters))
    map.attemptResize(QgsLayoutSize(200, 180, QgsUnitTypes.LayoutMillimeters))

    legend = QgsLayoutItemLegend(layout)
    legend.setTitle("Legend")
    layerTree = QgsLayerTree()
    layerTree.addLayer(layer)
    legend.model().setRootGroup(layerTree)
    layout.addLayoutItem(legend)
    legend.attemptMove(QgsLayoutPoint(245, 5, QgsUnitTypes.LayoutMillimeters))

    scalebar = QgsLayoutItemScaleBar(layout)
    scalebar.setStyle('Line Ticks Up')
    scalebar.setUnits(QgsUnitTypes.DistanceKilometers)
    scalebar.setNumberOfSegments(4)
    scalebar.setNumberOfSegmentsLeft(0)
    scalebar.setUnitsPerSegment(0.5)
    scalebar.setLinkedMap(map)
    scalebar.setUnitLabel('km')
    scalebar.setFont(QFont('Arial', 14))
    scalebar.update()
    layout.addLayoutItem(scalebar)
    scalebar.attemptMove(QgsLayoutPoint(200, 190, QgsUnitTypes.LayoutMillimeters))

    title = QgsLayoutItemLabel(layout)
    title.setText(each)
    title.setFont(QFont('Arial', 24))
    title.adjustSizeToText()
    layout.addLayoutItem(title)
    title.attemptMove(QgsLayoutPoint(10, 5, QgsUnitTypes.LayoutMillimeters))

    #checking theme names can be accessed:
    themes = QgsProject.instance().mapThemeCollection().mapThemes()
    print(themes)

    layout = manager.layoutByName(layoutName)
    exporter = QgsLayoutExporter(layout)

    fn = 'C:/export/' + each + '.png'
    exporter.exportToImage(fn, QgsLayoutExporter.ImageExportSettings())
    #exporter.exportToPdf(fn, QgsLayoutExporter.PdfExportSettings())
2
  • Qgsmapcollection? Did you mean QgsMapThemeCollection? Jan 31, 2020 at 21:45
  • yes, sorry, I have edited my question. It's not in the code though because I don't know how to use it.
    – Leo
    Jan 31, 2020 at 22:32

2 Answers 2

3

try inserting the following 2 lines of code after:

ms.setLayers([layer])  #set layers to be mapped

insert these:

map.setFollowVisibilityPreset(True)
map.setFollowVisibilityPresetName(each)

It's the same as ticking the 'Follow map theme' in the item properties of your layout mapmap item properties

1
  • yep, thank you so much, this solved it perfectly
    – Leo
    Feb 3, 2020 at 0:05
1

This also does the trick instead of relying on themes:

QgsProject.instance().layerTreeRoot().findLayer(name_of_the_layer_in_project.id()).setItemVisibilityChecked(False)

Your Answer

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

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