Why Automate Map Production?
Journalists, researchers, and GIS professionals often need dozens or even hundreds of maps to tell a story or support an analysis. Creating each map manually in QGIS is time‑consuming, error‑prone, and scales poorly. By pairing QGIS with Python, you can generate a full map series in minutes, keep styling consistent, and free up valuable time for deeper insight.
What You’ll Need
- QGIS 3.x installed on your workstation.
- Python 3.8+ (bundled with QGIS, but a separate install works too).
- The qgis Python package accessible via the QGIS Python console or a virtual environment.
- A basic project file (*.qgz) with layers, symbology, and layout ready for automation.
- CSV or JSON file that contains the variables you want to iterate over (e.g., dates, regions, or data layers).
Step 1 – Prepare Your QGIS Layout
Open QGIS and design a layout that will serve as the template for all generated maps. Include placeholders for dynamic elements such as the title, date, and legend. Use the Expression Based Text feature for items like the map title so you can replace them via Python later.
Make sure to save the layout with a clear name, for example master_layout.qgz. This file will be referenced by the script.
Step 2 – Organize Your Data Sources
The power of automation lies in feeding the script a list of parameters. Create a CSV called map_params.csv with columns like region, date, and layer_path. Each row represents one map you want to output.
region,date,layer_path
"North",2024-01-01,/data/north.shp
"South",2024-01-01,/data/south.shp
"East",2024-01-01,/data/east.shp
Keep the file in the same folder as your QGIS project for easy path resolution.
Step 3 – Write the Python Automation Script
Below is a fully functional script you can paste into the QGIS Python Console or run as a standalone script. It reads the CSV, updates the layout, and exports each map as a high‑resolution PNG.
import os
import csv
from qgis.core import (
QgsApplication,
QgsProject,
QgsLayoutExporter,
QgsLayoutItemMap,
QgsExpressionContext,
QgsExpressionContextUtils,
)
# ---------- Initialise QGIS (only needed for standalone runs) ----------
qgs = QgsApplication([], False)
qgs.initQgis()
project = QgsProject.instance()
project.read('master_layout.qgz')
layout = project.layoutManager().layoutByName('Map Layout')
exporter = QgsLayoutExporter(layout)
# Path to CSV with parameters
csv_path = 'map_params.csv'
output_dir = 'generated_maps'
os.makedirs(output_dir, exist_ok=True)
with open(csv_path, newline='') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
# 1️⃣ Update dynamic text items
for item in layout.items():
if hasattr(item, 'setText'):
txt = item.text()
txt = txt.replace('{region}', row['region'])
txt = txt.replace('{date}', row['date'])
item.setText(txt)
# 2️⃣ Replace the layer source
layer = project.mapLayersByName('data_layer')[0]
layer.setDataSource(row['layer_path'], layer.name(), 'ogr')
layer.triggerRepaint()
# 3️⃣ Export the map
out_path = os.path.join(output_dir, f"{row['region']}_{row['date']}.png")
result = exporter.exportToImage(out_path, QgsLayoutExporter.ImageExportSettings())
if result == QgsLayoutExporter.Success:
print(f"Exported {out_path}")
else:
print(f"Failed to export {out_path}")
# ---------- Clean up ----------
qgs.exitQgis()
Key points in the script:
- Dynamic Text Replacement: The placeholders
{region}and{date}in your layout are swapped with values from each CSV row. - Layer Swapping: The script points the generic
data_layerto a new shapefile or GeoPackage for every iteration. - Batch Export: Each map is saved automatically, naming the file with the region and date for easy cataloging.
Step 4 – Run, Test, and Refine
Execute the script. If you see errors about missing layers, double‑check the layer name in the QGIS project matches the name used in project.mapLayersByName('data_layer').... Adjust the CSV column names or placeholder syntax if needed.
Iterate a few times: change the layout style, add a north arrow, or tweak the legend. Because the process is scripted, you can re‑run the whole batch in seconds after each tweak.
Best Practices for Scalable Map Automation
- Version Control: Keep your QGIS project and Python script in a Git repository. It makes rolling back changes painless.
- Modular Code: Break the script into functions (e.g.,
update_text(),swap_layer(),export_map()) for readability and reuse. - Logging: Write a simple log file that records each export’s success or failure. This is crucial when generating thousands of maps.
- Performance Tips: Disable unnecessary layers, use low‑resolution previews during development, and only enable high‑resolution export at the final step.
- File Naming Conventions: Include key metadata in the filename (region, date, scenario) to keep the output folder searchable.
Conclusion – Turn Repetition into Efficiency
By combining QGIS’s powerful cartographic engine with Python’s automation capabilities, you can transform a labor‑intensive task into a repeatable workflow. Whether you’re producing daily news maps, seasonal environmental reports, or a series of election precinct visualisations, the approach outlined here scales effortlessly.
Ready to give it a try? Download the starter GitHub repository, adapt the CSV to your data, and watch your map collection grow in minutes.
Take the next step: Subscribe to our newsletter for more GIS tutorials, or contact us for a custom automation solution tailored to your newsroom’s needs.