I try to make a print-layout consisting of 2 maps-items. I only use one layer, but I want to picture it in different styles.
First, as it is when loaded, and on the second map in another style (which I load from a file). I used a template for the layout production (https://opensourceoptions.com/blog/pyqgis-create-and-print-a-map-layout-with-python/) an adapted it. Then I red the advice from bbsea (How to lock LayoutItem layers in QGIS 3.0 using python?) and used map.storeCurrentLayerStyles()
, still it is not working.
To put it in pictures, this is what I want:
but this is what I get:
Here is the code I use:
from qgis.PyQt import QtGui
layer_list = iface.mapCanvas().layers()
project = QgsProject.instance()
manager = project.layoutManager()
layoutName = 'Test1'
layouts_list = manager.printLayouts()
layout = QgsPrintLayout(project)
layout.initializeDefaults()
layout.setName(layoutName)
manager.addLayout(layout)
layer = layer_list[0]
# first map:
map = QgsLayoutItemMap(layout)
map.setRect(60, 20, 60, 20)
ms = QgsMapSettings()
ms.setLayers([layer])
rect = QgsRectangle(ms.fullExtent())
rect.scale(1.0)
ms.setExtent(rect)
map.setExtent(rect)
map.setBackgroundColor(QColor(255, 255, 255, 0))
layout.addLayoutItem(map)
map.attemptMove(QgsLayoutPoint(5, 5, QgsUnitTypes.LayoutMillimeters))
map.attemptResize(QgsLayoutSize(90, 90, QgsUnitTypes.LayoutMillimeters))
map.storeCurrentLayerStyles()
# second map:
map2 = QgsLayoutItemMap(layout)
map2.setRect(60, 20, 60, 20)
ms2 = QgsMapSettings()
layer.loadNamedStyle('/home/..../style.qml')
layer.triggerRepaint()
ms2.setLayers([layer])
rect2 = QgsRectangle(ms2.fullExtent())
rect2.scale(1.0)
ms2.setExtent(rect2)
map2.setExtent(rect2)
map2.setBackgroundColor(QColor(255, 255, 255, 0))
layout.addLayoutItem(map2)
map2.attemptMove(QgsLayoutPoint(95, 95, QgsUnitTypes.LayoutMillimeters))
map2.attemptResize(QgsLayoutSize(90, 90, QgsUnitTypes.LayoutMillimeters))
map2.storeCurrentLayerStyles()
layout = manager.layoutByName(layoutName)
exporter = QgsLayoutExporter(layout)
fn = '/home/c/mapTest.pdf'
exporter.exportToPdf(fn, QgsLayoutExporter.PdfExportSettings())
How can I lock the layer-style in?
-
Did you have a look at map themes? See: docs.qgis.org/3.16/en/docs/user_manual/introduction/…Babel– Babel2021年09月09日 07:16:06 +00:00Commented Sep 9, 2021 at 7:16
-
Not really. I would like to code it... it is part of a bigger project.Carina– Carina2021年09月09日 08:06:55 +00:00Commented Sep 9, 2021 at 8:06
-
Thanks for the idea, but still the 1.map is changing...Carina– Carina2021年09月09日 10:31:46 +00:00Commented Sep 9, 2021 at 10:31
2 Answers 2
I'm afraid that I can't really provide an intelligent or scientific explanation of the problem here, because I tried modifying your code and I was not able to get a satisfactory result.
But it works for me with the following code snippet which I tested on a similar data set to what you have shown.
project = QgsProject.instance()
layout = QgsPrintLayout(project)
layout.initializeDefaults()
layout.setName('Test1')
project.layoutManager().addLayout(layout)
layer_list = iface.mapCanvas().layers()
layer = layer_list[0]
map1 = QgsLayoutItemMap(layout)
map1.attemptMove(QgsLayoutPoint(5,50, QgsUnitTypes.LayoutMillimeters))
map1.attemptResize(QgsLayoutSize(125,85, QgsUnitTypes.LayoutMillimeters))
map1.setExtent(layer.extent())
map1.setLayers([layer])
layout.addLayoutItem(map1)
map1.storeCurrentLayerStyles()
map1.setKeepLayerSet(True)
map1.setKeepLayerStyles(True)
map2 = QgsLayoutItemMap(layout)
map2.attemptMove(QgsLayoutPoint(150,50, QgsUnitTypes.LayoutMillimeters))
map2.attemptResize(QgsLayoutSize(125,85, QgsUnitTypes.LayoutMillimeters))
#change path to your own saved style file
layer.loadNamedStyle('C:\\Users\\Ben\\Desktop\\Layer_styles\\test_style.qml')
layer.triggerRepaint()
map2.setExtent(layer.extent())
map2.setLayers([layer])
layout.addLayoutItem(map2)
The result is:
The required api call seems to be:
map1.setKeepLayerStyles(True)
Because if I just comment out that single line, the stored style for map 1 is not locked and changes to follow the new style applied as in the problem you describe.
-
It works : ) Thank you VERY much!Carina– Carina2021年09月10日 04:58:13 +00:00Commented Sep 10, 2021 at 4:58
In addition to Ben's answer, I noticed that at in my case methods setKeepLayerSet
and setKeepLayerStyles
are not working when layer styles are changed and exsiting map is updated.
My case with an issue:
- Created a map and added it to layout.
- Set both
setKeepLayerSet
andsetKeepLayerStyles
toTrue
- Changed styles of layers in main QGIS window
- Moved existing map in layout
As a result styles were also changed despite ticks on setKeepLayerSet
and setKeepLayerStyles
options. Hovewer when placing these ticks manually, everything works well and changing layer styles or moving map bounds would not affect styles of layers on map.
Recently I found a method called layerStyleOverrides
(QGIS Documentation link). It can save all layer styles in a map object and then it can be used as a variable for setLayerStyleOverrides
method.
And here is a code sample:
style_1 = r"D:\GIS\bm\style_1.qml" # assuming layer has this style
style_2 = r"D:\GIS\bm\style_2.qml" # this is a style which need to be set
current_style = map1.layerStyleOverrides() # storing styles of current map including first style of layer
layer.loadNamedStyle(style_2) # loading second style for a layer
map1.setLayerStyleOverrides(current_style) # overriding style for map including first style
map1.attemptMove(QgsLayoutPoint(15,50, QgsUnitTypes.LayoutMillimeters)) # moving map to see changes (can be replaced with some update method of layout)
Finally we have our layer with the second style set in main QGIS window but with the first style in layout window.