I use QGIS3 and I have project with series of heatmap raster layers from different years (Grass_Snake_2005-2024, one raster layer for each year), in this project I set up already map in map Print Composer. I need to make number of series of maps where I need just change active raster layer in Layer Panel and update year in title in Print Composer.
I write this Python script below, but currently it produce all series with different years but with one still same raster layer, how I can fix that python code that it will be iterate through raster layers and save all series with different raster layers depending to the year of the survey, where is my mistake?
from qgis.core import QgsProject, QgsLayoutExporter, QgsMapLayer
# Function to update print composer title
def update_title(layout, year):
composer_title = layout.itemById('Title')
composer_title.setText(f"Distribution of Grass Snakes in the Rhydymwyn Valley, {year}")
# Get the layout
layout = QgsProject.instance().layoutManager().layoutByName('Grass_Snakes')
# Check if layout is found
if layout is None:
print("Layout 'Grass Snakes' not found.")
exit()
# Get all raster layers in the project
raster_layers = QgsProject.instance().mapLayers().values()
# Iterate through raster layers and extract years
years = []
for layer in raster_layers:
if isinstance(layer, QgsMapLayer) and layer.type() == QgsMapLayer.RasterLayer and layer.name().startswith('Grass Snake'):
year = layer.name().split()[-1] # Extract year from layer name
years.append(int(year))
# Sort the years in ascending order
years.sort()
# Iterate through years and update print composer title
for year in years:
# Update print composer title for each year
update_title(layout, year)
# Export the layout to an image (adjust the file path accordingly)
image_path = f'L:/GIS/Reptiles/Maps/Grass Snake/Logo/Grass_Snake_{year}.jpeg'
exporter = QgsLayoutExporter(layout)
exporter.exportToImage(image_path, QgsLayoutExporter.ImageExportSettings())
print(f"Image exported for year {year}")
1 Answer 1
I see a couple of issues.
Nowhere are you updating the layer in the map item of the layout. So, it continues to display only what is on your current map canvas.
The lines of code at the bottom, that do the exporting, are outside your loop. So they will only work once, for whatever the loop outputs on its last iteration.
I have made some adaptations, namely:
- sorted the list of raster layers based on their year. This way there is no need to make a separate list of years.
- performed the validation when making the list of raster layers rather then in the main loop (not strictly necessary but makes the
raster_layers
variable name more explicit). - moved the
update_title()
call inside the loop - set the map item's layers with the current raster layer each loop iteration
- moved the exporting to image code inside the loop
Note, if you desire more layers than just the distribution raster on your exported image, the other layers will need to be referenced and then added in the map_item.setLayers()
call (order is top-bottom).
from qgis.core import QgsProject, QgsLayoutExporter, QgsMapLayer
# Function to update print composer title
def update_title(layout, year):
composer_title = layout.itemById('Title')
composer_title.setText(f"Distribution of Grass Snakes in the Rhydymwyn Valley, {year}")
# Get the layout
layout = QgsProject.instance().layoutManager().layoutByName('Grass_Snakes')
# Check if layout is found
if layout is None:
print("Layout 'Grass Snakes' not found.")
exit()
# Get the map item in the layout (can also use layout.itemById if you have given it a specific name)
map_item = [x for x in layout.items() if isinstance(x, QgsLayoutItemMap)][0]
# Get all raster layers in the project beginning with 'Grass Snake'
raster_layers = [x for x in QgsProject.instance().mapLayers().values() if isinstance(x, QgsRasterLayer) and layer.name().startswith('Grass Snake')]
# Sort the raster layers based on the year in their name
raster_layers = [x for x in sorted(raster_layers, key=lambda item: int(item.name().split()[-1]))]
# Iterate through raster layers
for layer in raster_layers:
# Extract year from layer name
year = layer.name().split()[-1]
# Update the title
update_title(layout, year)
# Pass the layer to the map item
map_item.setLayers([layer])
# Export the layout to an image (adjust the file path accordingly)
image_path = f'L:/GIS/Reptiles/Maps/Grass Snake/Logo/Grass_Snake_{year}.jpeg'
exporter = QgsLayoutExporter(layout)
exporter.exportToImage(image_path, QgsLayoutExporter.ImageExportSettings())
print(f"Image exported for year {year}")