
Qgis Agents Map Generator
- 8 installs
- 29 repo stars
- Updated July 8, 2026
- openaec-foundation/qgis-claude-skill-package
Helps with ai & agent building tasks.
About
qgis-agents-map-generator is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- qgis-agents-map-generator
- AI & Agent Building
- AI-coding skill
Qgis Agents Map Generator by the numbers
- 8 all-time installs (skills.sh)
- Ranked #12,339 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/openaec-foundation/qgis-claude-skill-package --skill qgis-agents-map-generatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 8 |
|---|---|
| repo stars | ★ 29 |
| Last updated | July 8, 2026 |
| Repository | openaec-foundation/qgis-claude-skill-package ↗ |
What it does
Helps with ai & agent building tasks.
Files
qgis-agents-map-generator
Quick Reference
Map Generation Pipeline
| Step | Action | Key Classes |
|---|---|---|
| 1. Data Loading | Load vector/raster layers, validate | QgsVectorLayer, QgsRasterLayer |
| 2. CRS Setup | Set project CRS, reproject if needed | QgsCoordinateReferenceSystem, QgsProject |
| 3. Symbology | Apply renderer matching data type | QgsCategorizedSymbolRenderer, QgsGraduatedSymbolRenderer |
| 4. Labeling | Configure label placement and format | QgsPalLayerSettings, QgsTextFormat |
| 5. Layout | Create print layout with map items | QgsPrintLayout, QgsLayoutItemMap |
| 6. Cartographic Elements | Add legend, scale bar, north arrow, title | QgsLayoutItemLegend, QgsLayoutItemScaleBar |
| 7. Export | Export to PDF/PNG/SVG | QgsLayoutExporter |
Export Format Decision
| Format | When to Use |
|---|---|
| Print-ready output, multi-page documents, atlas exports | |
| PNG | Web display, raster-only output, fixed resolution |
| SVG | Editable vector output, post-processing in Illustrator/Inkscape |
---
Critical Warnings
NEVER export a layout without first setting the map extent — this produces blank or mispositioned maps. ALWAYS call map_item.zoomToExtent() or map_item.setExtent() before export.
ALWAYS call layout.initializeDefaults() after creating a new QgsPrintLayout — without this, the layout has no pages and export fails silently.
NEVER export without checking the result code from QgsLayoutExporter — result 0 means success; any other value indicates a specific failure (memory, file, print, SVG layer, or iterator error).
ALWAYS call layer.triggerRepaint() after changing symbology or labeling — without this, the map canvas and layout exports render stale styles.
NEVER use QgsRandomColorRamp for thematic maps — random colors destroy visual hierarchy and make maps unreadable. ALWAYS select a color ramp matching the data type (sequential, diverging, or qualitative).
ALWAYS link the legend, scale bar, and overview items to the correct map item via setLinkedMap() — unlinked items display incorrect or empty content.
ALWAYS verify layer.isValid() immediately after loading — invalid layers produce empty maps without error messages.
---
Map Generation Pipeline
This skill orchestrates the FULL pipeline from raw data to exported map. Follow these steps in order.
Step 1: Data Loading
from qgis.core import QgsVectorLayer, QgsRasterLayer, QgsProject
project = QgsProject.instance()
# Vector layer
vlayer = QgsVectorLayer("/path/to/data.gpkg|layername=buildings", "Buildings", "ogr")
assert vlayer.isValid(), f"Layer failed to load: {vlayer.error().summary()}"
project.addMapLayer(vlayer)
# Raster layer
rlayer = QgsRasterLayer("/path/to/dem.tif", "DEM")
assert rlayer.isValid(), f"Raster failed to load: {rlayer.error().summary()}"
project.addMapLayer(rlayer)Step 2: CRS Setup
from qgis.core import QgsCoordinateReferenceSystem
# Set project CRS: ALWAYS use a projected CRS for maps with scale bars
project_crs = QgsCoordinateReferenceSystem("EPSG:28992") # Example: Dutch RD New
project.setCrs(project_crs)CRS Selection Rules:
- ALWAYS use a projected CRS (meters/feet) for maps with scale bars or area measurements
- NEVER use EPSG:4326 (geographic) for print maps — degree-based coordinates distort scale bars
- Use UTM zones for maps covering < 6 degrees of longitude
- Use national grid systems (e.g., EPSG:28992, EPSG:27700) for country-specific maps
Step 3: Symbology
Select renderer based on data characteristics. See the Symbology Decision Tree below.
from qgis.core import (
QgsMarkerSymbol, QgsLineSymbol, QgsFillSymbol,
QgsCategorizedSymbolRenderer, QgsGraduatedSymbolRenderer,
QgsRuleBasedRenderer, QgsRendererCategory, QgsRendererRange,
QgsClassificationRange, QgsStyle
)
# Apply renderer to layer
layer.setRenderer(renderer)
layer.triggerRepaint()Step 4: Labeling
from qgis.core import QgsPalLayerSettings, QgsVectorLayerSimpleLabeling, QgsTextFormat
from qgis.PyQt.QtGui import QColor
settings = QgsPalLayerSettings()
settings.fieldName = 'name'
settings.isExpression = False
settings.enabled = True
text_format = QgsTextFormat()
text_format.setSize(10)
text_format.setColor(QColor('black'))
# ALWAYS add a buffer (halo) for readability
buffer_settings = text_format.buffer()
buffer_settings.setEnabled(True)
buffer_settings.setSize(1.0)
buffer_settings.setColor(QColor('white'))
settings.setFormat(text_format)
labeling = QgsVectorLayerSimpleLabeling(settings)
layer.setLabeling(labeling)
layer.setLabelsEnabled(True)
layer.triggerRepaint()Step 5: Layout Creation
from qgis.core import (
QgsPrintLayout, QgsLayoutItemMap, QgsLayoutSize,
QgsLayoutPoint, QgsUnitTypes
)
layout = QgsPrintLayout(project)
layout.initializeDefaults() # CRITICAL: creates default A4 page
layout.setName("Generated Map")
# Add map item
map_item = QgsLayoutItemMap(layout)
map_item.attemptResize(QgsLayoutSize(260, 180, QgsUnitTypes.LayoutMillimeters))
map_item.attemptMove(QgsLayoutPoint(15, 25, QgsUnitTypes.LayoutMillimeters))
map_item.zoomToExtent(vlayer.extent())
layout.addLayoutItem(map_item)
# Register layout with project
project.layoutManager().addLayout(layout)Step 6: Cartographic Elements
from qgis.core import (
QgsLayoutItemLabel, QgsLayoutItemLegend,
QgsLayoutItemScaleBar, QgsLayoutItemPicture
)
# Title
title = QgsLayoutItemLabel(layout)
title.setText("Map Title")
title.setFont(QFont("Arial", 18))
title.adjustSizeToText()
title.attemptMove(QgsLayoutPoint(15, 5, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(title)
# Legend: ALWAYS link to map item
legend = QgsLayoutItemLegend(layout)
legend.setLinkedMap(map_item)
legend.attemptMove(QgsLayoutPoint(15, 210, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(legend)
# Scale bar: ALWAYS link to map item
scalebar = QgsLayoutItemScaleBar(layout)
scalebar.setStyle("Single Box")
scalebar.setLinkedMap(map_item)
scalebar.applyDefaultSize()
scalebar.attemptMove(QgsLayoutPoint(120, 210, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(scalebar)
# North arrow
north_arrow = QgsLayoutItemPicture(layout)
north_arrow.setPicturePath(":/images/sketchy/sketchy-north.svg")
north_arrow.attemptResize(QgsLayoutSize(15, 15, QgsUnitTypes.LayoutMillimeters))
north_arrow.attemptMove(QgsLayoutPoint(265, 25, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(north_arrow)
# Source attribution
source = QgsLayoutItemLabel(layout)
source.setText("Source: [data source attribution]")
source.adjustSizeToText()
source.attemptMove(QgsLayoutPoint(15, 202, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(source)Step 7: Export
from qgis.core import QgsLayoutExporter
exporter = QgsLayoutExporter(layout)
# PDF export (most common)
pdf_settings = QgsLayoutExporter.PdfExportSettings()
pdf_settings.dpi = 300
result = exporter.exportToPdf("/path/to/output.pdf", pdf_settings)
assert result == QgsLayoutExporter.ExportResult.Success, f"Export failed: {result}"
# PNG export
img_settings = QgsLayoutExporter.ImageExportSettings()
img_settings.dpi = 300
result = exporter.exportToImage("/path/to/output.png", img_settings)
# SVG export
svg_settings = QgsLayoutExporter.SvgExportSettings()
svg_settings.dpi = 300
result = exporter.exportToSvg("/path/to/output.svg", svg_settings)---
Symbology Decision Tree
Follow this tree to select the correct renderer:
Is the data CATEGORICAL (text/classes)?
├── YES → Are there ≤ 20 unique values?
│ ├── YES → Use QgsCategorizedSymbolRenderer
│ │ Color ramp: QUALITATIVE (distinct hues)
│ └── NO → Use QgsRuleBasedRenderer with grouped categories
│ Or simplify categories before rendering
└── NO → Is the data NUMERIC?
├── YES → Is the data SEQUENTIAL (low-to-high)?
│ ├── YES → Use QgsGraduatedSymbolRenderer
│ │ Color ramp: SEQUENTIAL (light-to-dark single hue)
│ └── NO → Is there a meaningful MIDPOINT (e.g., zero, average)?
│ ├── YES → Use QgsGraduatedSymbolRenderer
│ │ Color ramp: DIVERGING (two hues from midpoint)
│ └── NO → Use QgsGraduatedSymbolRenderer
│ Color ramp: SEQUENTIAL
└── NO → Use QgsSingleSymbolRenderer (uniform style)Color Ramp Selection
| Data Type | Ramp Type | Example Use | PyQGIS Class |
|---|---|---|---|
| Sequential numeric | Sequential | Population density, elevation | QgsGradientColorRamp |
| Diverging numeric | Diverging | Temperature anomaly, profit/loss | QgsGradientColorRamp (two-tone) |
| Categorical | Qualitative | Land use types, building classes | QgsPresetSchemeColorRamp |
| Continuous surface | Sequential | DEM hillshade, slope | QgsGradientColorRamp |
# Sequential color ramp (light yellow to dark red)
from qgis.core import QgsGradientColorRamp
from qgis.PyQt.QtGui import QColor
ramp = QgsGradientColorRamp(QColor('#ffffb2'), QColor('#bd0026'))
# Use named style ramps from QGIS
style = QgsStyle.defaultStyle()
ramp = style.colorRamp('Spectral') # or 'Blues', 'RdYlGn', 'Viridis', etc.Geometry-Specific Symbol Creation
| Geometry | Class | Example |
|---|---|---|
| Point | QgsMarkerSymbol | QgsMarkerSymbol.createSimple({'name': 'circle', 'color': 'red', 'size': '3'}) |
| Line | QgsLineSymbol | QgsLineSymbol.createSimple({'color': 'blue', 'width': '0.5'}) |
| Polygon | QgsFillSymbol | QgsFillSymbol.createSimple({'color': '#aaffaa', 'outline_color': 'black', 'outline_width': '0.3'}) |
---
Layout Guide
Standard Page Sizes
| Size | Width x Height (mm) | Use Case |
|---|---|---|
| A4 Portrait | 210 x 297 | Reports, standard prints |
| A4 Landscape | 297 x 210 | Wide-area maps |
| A3 Portrait | 297 x 420 | Detailed maps |
| A3 Landscape | 420 x 297 | Panoramic maps |
| A0 | 841 x 1189 | Wall maps, posters |
# Set page size
page = layout.pageCollection().page(0)
page.setPageSize(QgsLayoutSize(420, 297, QgsUnitTypes.LayoutMillimeters)) # A3 LandscapeLayout Margin Guidelines
| Element | Recommended Margin (mm) |
|---|---|
| Page margins | 10-15 on all sides |
| Map frame to edge | 15 minimum |
| Title above map | 5-10 gap |
| Legend below/beside map | 5 gap from map edge |
| Scale bar | Bottom of map area |
| North arrow | Top-right corner of map |
Cartographic Checklist
Every generated map MUST include: 1. Title — descriptive, top of layout 2. Legend — linked to map item, shows all visible layers 3. Scale bar — linked to map item, uses projected CRS 4. North arrow — indicates orientation 5. Source attribution — data source credits 6. Date — when the map was produced
---
Atlas Generation
Use atlas for batch-generating maps per feature (e.g., one map per municipality).
atlas = layout.atlas()
atlas.setCoverageLayer(coverage_layer)
atlas.setEnabled(True)
atlas.setFilenameExpression("'map_' || \"name\"")
# Optional: filter features
# atlas.setFilterFeatures(True)
# atlas.setFilterExpression('"status" = \'active\'')
# Map item MUST be controlled by atlas
map_item.setAtlasDriven(True)
map_item.setAtlasScalingMode(QgsLayoutItemMap.AtlasScalingMode.Auto)
# Export all atlas pages to individual PDFs
pdf_settings = QgsLayoutExporter.PdfExportSettings()
pdf_settings.dpi = 300
result = QgsLayoutExporter.exportToPdfs(
atlas, "/path/to/atlas_output/", pdf_settings
)Atlas Expression Variables:
@atlas_featurenumber— current feature index (1-based)@atlas_totalfeatures— total number of features@atlas_feature— current feature object@atlas_featureid— current feature ID@atlas_pagename— current page name
---
Export Guide
DPI Selection
| Purpose | DPI | File Size |
|---|---|---|
| Screen/web preview | 96 | Small |
| Standard print | 150 | Medium |
| High-quality print | 300 | Large |
| Publication quality | 600 | Very large |
Export Result Codes
| Code | Constant | Meaning |
|---|---|---|
| 0 | Success | Export completed |
| 1 | Canceled | User canceled |
| 2 | MemoryError | Insufficient memory (reduce DPI or map size) |
| 3 | FileError | Cannot write to output path |
| 4 | PrintError | Print rendering failed |
| 5 | SvgLayerError | SVG layer export failed |
| 6 | IteratorError | Atlas iteration failed |
Template Save/Load for Reuse
from qgis.core import QgsReadWriteContext
from qgis.PyQt.QtXml import QDomDocument
# Save layout as .qpt template
doc = QDomDocument()
layout.writeXml(doc, QgsReadWriteContext())
with open("/path/to/template.qpt", "w") as f:
f.write(doc.toString())
# Load layout from .qpt template
with open("/path/to/template.qpt", "r") as f:
content = f.read()
doc = QDomDocument()
doc.setContent(content)
new_layout = QgsPrintLayout(project)
new_layout.readXml(doc.documentElement(), doc, QgsReadWriteContext())
new_layout.setName("From Template")
project.layoutManager().addLayout(new_layout)---
MCP Integration
For runtime map generation via Claude Code, use MCP servers that expose QGIS functionality:
- qgis-mcp-server — Provides tool-based access to QGIS project manipulation, layer management, and export
- Processing MCP — Exposes QGIS Processing algorithms as MCP tools
When an MCP server is available, the map generation pipeline steps remain identical — the MCP server wraps the same PyQGIS calls described above. ALWAYS validate layer loading and export results through the MCP response.
---
Validation Checklist
Before delivering a generated map, verify ALL items:
- [ ] All layers loaded successfully (
isValid() == True) - [ ] Project CRS is a projected system (not geographic/EPSG:4326)
- [ ] Symbology matches the data type (categorical/graduated/single)
- [ ] Color ramp matches data semantics (sequential/diverging/qualitative)
- [ ] Labels have buffer/halo enabled for readability
- [ ] Layout has title, legend, scale bar, north arrow, source attribution
- [ ] Legend is linked to the map item
- [ ] Scale bar is linked to the map item
- [ ] Map extent is set before export (not empty/default)
- [ ] Export result code is
Success(0) - [ ] Output file exists and has non-zero size
- [ ] DPI matches intended use (300 for print, 96 for screen)
---
Reference Links
- references/methods.md — API signatures for map generation classes
- references/examples.md — Complete working map generation examples
- references/anti-patterns.md — Common map generation mistakes and fixes
Official Sources
- https://qgis.org/pyqgis/3.x/core/QgsPrintLayout.html
- https://qgis.org/pyqgis/3.x/core/QgsLayoutExporter.html
- https://qgis.org/pyqgis/3.x/core/QgsCategorizedSymbolRenderer.html
- https://qgis.org/pyqgis/3.x/core/QgsGraduatedSymbolRenderer.html
- https://docs.qgis.org/3.34/en/docs/pyqgis_developer_cookbook/composer.html
qgis-agents-map-generator — Anti-Patterns
AP-1: Exporting Without Setting Map Extent
Wrong:
layout = QgsPrintLayout(project)
layout.initializeDefaults()
map_item = QgsLayoutItemMap(layout)
map_item.attemptResize(QgsLayoutSize(200, 150, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(map_item)
# Directly export — map extent is empty
exporter = QgsLayoutExporter(layout)
exporter.exportToPdf("/output/map.pdf", QgsLayoutExporter.PdfExportSettings())Why it fails: The map item has no extent set. The export produces a blank or incorrectly positioned map with no visible data.
Correct:
map_item = QgsLayoutItemMap(layout)
map_item.attemptResize(QgsLayoutSize(200, 150, QgsUnitTypes.LayoutMillimeters))
map_item.zoomToExtent(layer.extent()) # ALWAYS set extent before export
layout.addLayoutItem(map_item)---
AP-2: Missing initializeDefaults() Call
Wrong:
layout = QgsPrintLayout(project)
layout.setName("My Map")
# No initializeDefaults() — layout has zero pages
map_item = QgsLayoutItemMap(layout)
layout.addLayoutItem(map_item)Why it fails: Without initializeDefaults(), the layout has no pages. Items are added to a non-existent page, and export produces empty output or fails.
Correct:
layout = QgsPrintLayout(project)
layout.initializeDefaults() # ALWAYS call this immediately after construction
layout.setName("My Map")---
AP-3: Ignoring Export Result Codes
Wrong:
exporter = QgsLayoutExporter(layout)
exporter.exportToPdf("/output/map.pdf", pdf_settings)
# Assume success — no result check
print("Export complete!")Why it fails: The export may fail due to memory errors, file permission issues, or rendering problems. Without checking the result code, the script reports success when the output file is missing or corrupt.
Correct:
result = exporter.exportToPdf("/output/map.pdf", pdf_settings)
if result != QgsLayoutExporter.ExportResult.Success:
raise RuntimeError(f"Export failed with code: {result}")---
AP-4: Using Random Colors for Thematic Maps
Wrong:
from qgis.core import QgsRandomColorRamp
renderer = QgsGraduatedSymbolRenderer()
renderer.setSourceColorRamp(QgsRandomColorRamp())Why it fails: Random colors destroy visual hierarchy. A graduated map needs sequential or diverging colors so readers can intuitively understand high vs. low values. Random colors make the map unreadable.
Correct:
# Sequential ramp for sequential data
ramp = QgsGradientColorRamp(QColor('#ffffcc'), QColor('#800026'))
renderer.setSourceColorRamp(ramp)
# Or use a named style ramp
ramp = QgsStyle.defaultStyle().colorRamp('YlOrRd')
renderer.setSourceColorRamp(ramp)---
AP-5: Unlinked Legend or Scale Bar
Wrong:
legend = QgsLayoutItemLegend(layout)
legend.attemptMove(QgsLayoutPoint(15, 200, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(legend)
# Legend is not linked to any map itemWhy it fails: An unlinked legend shows all project layers regardless of the map item's visible layers and extent. An unlinked scale bar shows incorrect or default scale values.
Correct:
legend = QgsLayoutItemLegend(layout)
legend.setLinkedMap(map_item) # ALWAYS link to the map item
layout.addLayoutItem(legend)
scalebar = QgsLayoutItemScaleBar(layout)
scalebar.setLinkedMap(map_item) # ALWAYS link to the map item
layout.addLayoutItem(scalebar)---
AP-6: Using Geographic CRS (EPSG:4326) for Print Maps
Wrong:
project.setCrs(QgsCoordinateReferenceSystem("EPSG:4326"))
# Scale bar now shows degrees instead of metersWhy it fails: EPSG:4326 uses degrees as units. Scale bars display meaningless degree values. Distance measurements are incorrect because degrees have variable length depending on latitude.
Correct:
# Use a projected CRS with meter-based units
project.setCrs(QgsCoordinateReferenceSystem("EPSG:28992")) # Dutch RD New
# Or UTM zone appropriate for the data location
project.setCrs(QgsCoordinateReferenceSystem("EPSG:32632")) # UTM Zone 32N---
AP-7: Forgetting triggerRepaint() After Symbology Change
Wrong:
layer.setRenderer(new_renderer)
# Directly create layout — renderer change not reflected
layout = QgsPrintLayout(project)Why it fails: Without triggerRepaint(), the map canvas and layout renders use the previous (cached) symbology. The exported map shows stale styles.
Correct:
layer.setRenderer(new_renderer)
layer.triggerRepaint() # ALWAYS repaint after changing renderer or labeling---
AP-8: Labels Without Buffer (Halo)
Wrong:
settings = QgsPalLayerSettings()
settings.fieldName = 'name'
settings.enabled = True
text_format = QgsTextFormat()
text_format.setSize(10)
text_format.setColor(QColor('black'))
settings.setFormat(text_format)
# No buffer — labels disappear on dark backgroundsWhy it fails: Labels without a buffer blend into the background, especially over dark symbology or raster layers. They become unreadable on busy maps.
Correct:
text_format = QgsTextFormat()
text_format.setSize(10)
text_format.setColor(QColor('black'))
buffer_settings = text_format.buffer()
buffer_settings.setEnabled(True)
buffer_settings.setSize(1.0)
buffer_settings.setColor(QColor('white'))
settings.setFormat(text_format)---
AP-9: Not Validating Layer Before Map Generation
Wrong:
layer = QgsVectorLayer("/data/missing_file.shp", "Data", "ogr")
project.addMapLayer(layer)
# Layer is invalid — all downstream operations produce empty results
renderer = QgsCategorizedSymbolRenderer()
layer.setRenderer(renderer)Why it fails: An invalid layer has no features, no fields, and no extent. The map generation pipeline produces empty maps without any error indication.
Correct:
layer = QgsVectorLayer("/data/missing_file.shp", "Data", "ogr")
assert layer.isValid(), f"Layer failed to load: {layer.error().summary()}"
project.addMapLayer(layer)---
AP-10: Atlas Without setAtlasDriven(True) on Map Item
Wrong:
atlas = layout.atlas()
atlas.setCoverageLayer(districts)
atlas.setEnabled(True)
# Map item is NOT atlas-driven — all pages show the same extentWhy it fails: Without setAtlasDriven(True), the map item displays a static extent for every atlas page. Every exported page shows the same area instead of zooming to the current atlas feature.
Correct:
atlas = layout.atlas()
atlas.setCoverageLayer(districts)
atlas.setEnabled(True)
map_item.setAtlasDriven(True)
map_item.setAtlasScalingMode(QgsLayoutItemMap.AtlasScalingMode.Auto)---
AP-11: Mismatching Symbology Type and Geometry Type
Wrong:
# Layer contains polygons, but using marker symbol
symbol = QgsMarkerSymbol.createSimple({'name': 'circle', 'color': 'red'})
renderer = QgsSingleSymbolRenderer(symbol)
polygon_layer.setRenderer(renderer)Why it fails: Applying a marker symbol to a polygon layer produces no visible rendering. QGIS silently ignores the mismatched symbol type.
Correct:
# Match symbol type to geometry type
if polygon_layer.geometryType() == Qgis.GeometryType.Polygon:
symbol = QgsFillSymbol.createSimple({'color': 'red', 'outline_color': 'black'})
elif polygon_layer.geometryType() == Qgis.GeometryType.Line:
symbol = QgsLineSymbol.createSimple({'color': 'red', 'width': '0.5'})
elif polygon_layer.geometryType() == Qgis.GeometryType.Point:
symbol = QgsMarkerSymbol.createSimple({'name': 'circle', 'color': 'red'})
renderer = QgsSingleSymbolRenderer(symbol)
layer.setRenderer(renderer)---
AP-12: Hard-Coded Item Positions Exceeding Page Bounds
Wrong:
# A4 page is 210x297mm, but item placed at x=300
legend.attemptMove(QgsLayoutPoint(300, 200, QgsUnitTypes.LayoutMillimeters))Why it fails: Items placed outside the page bounds are not visible in the export. QGIS does not warn about off-page items.
Correct:
# ALWAYS verify positions are within page dimensions
page_size = layout.pageCollection().page(0).pageSize()
max_x = page_size.width() # e.g., 210 for A4 portrait
max_y = page_size.height() # e.g., 297 for A4 portrait
# Place within bounds
legend.attemptMove(QgsLayoutPoint(15, 200, QgsUnitTypes.LayoutMillimeters))qgis-agents-map-generator — Examples
Example 1: Choropleth Map from GeoPackage
Complete pipeline generating a choropleth (graduated color) map of population density from a GeoPackage, exported to PDF.
from qgis.core import (
QgsApplication, QgsProject, QgsVectorLayer,
QgsCoordinateReferenceSystem, QgsGraduatedSymbolRenderer,
QgsRendererRange, QgsClassificationRange, QgsFillSymbol,
QgsGradientColorRamp, QgsPalLayerSettings,
QgsVectorLayerSimpleLabeling, QgsTextFormat,
QgsPrintLayout, QgsLayoutItemMap, QgsLayoutItemLabel,
QgsLayoutItemLegend, QgsLayoutItemScaleBar,
QgsLayoutSize, QgsLayoutPoint, QgsUnitTypes,
QgsLayoutExporter
)
from qgis.PyQt.QtGui import QColor, QFont
project = QgsProject.instance()
# Step 1: Load data
layer = QgsVectorLayer("/data/municipalities.gpkg|layername=municipalities",
"Municipalities", "ogr")
assert layer.isValid(), "Layer failed to load"
project.addMapLayer(layer)
# Step 2: Set projected CRS
project.setCrs(QgsCoordinateReferenceSystem("EPSG:28992"))
# Step 3: Graduated symbology for population density
renderer = QgsGraduatedSymbolRenderer()
renderer.setClassAttribute('pop_density')
ramp = QgsGradientColorRamp(QColor('#ffffcc'), QColor('#800026'))
ranges = [
("Low", 0, 500, '#ffffcc'),
("Medium-Low", 500, 1000, '#fed976'),
("Medium", 1000, 2000, '#fd8d3c'),
("Medium-High", 2000, 5000, '#e31a1c'),
("High", 5000, 50000, '#800026'),
]
for label, lower, upper, color in ranges:
symbol = QgsFillSymbol.createSimple({
'color': color,
'outline_color': '#333333',
'outline_width': '0.2'
})
renderer.addClassRange(
QgsRendererRange(QgsClassificationRange(label, lower, upper), symbol)
)
layer.setRenderer(renderer)
layer.triggerRepaint()
# Step 4: Labels
settings = QgsPalLayerSettings()
settings.fieldName = 'name'
settings.enabled = True
text_format = QgsTextFormat()
text_format.setSize(8)
text_format.setColor(QColor('black'))
buffer_settings = text_format.buffer()
buffer_settings.setEnabled(True)
buffer_settings.setSize(0.8)
buffer_settings.setColor(QColor('white'))
settings.setFormat(text_format)
layer.setLabeling(QgsVectorLayerSimpleLabeling(settings))
layer.setLabelsEnabled(True)
layer.triggerRepaint()
# Step 5: Layout
layout = QgsPrintLayout(project)
layout.initializeDefaults()
layout.setName("Population Density Map")
map_item = QgsLayoutItemMap(layout)
map_item.attemptResize(QgsLayoutSize(180, 160, QgsUnitTypes.LayoutMillimeters))
map_item.attemptMove(QgsLayoutPoint(15, 25, QgsUnitTypes.LayoutMillimeters))
map_item.zoomToExtent(layer.extent())
layout.addLayoutItem(map_item)
# Step 6: Cartographic elements
title = QgsLayoutItemLabel(layout)
title.setText("Population Density by Municipality")
title.setFont(QFont("Arial", 16))
title.adjustSizeToText()
title.attemptMove(QgsLayoutPoint(15, 8, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(title)
legend = QgsLayoutItemLegend(layout)
legend.setLinkedMap(map_item)
legend.setTitle("Density (per km²)")
legend.attemptMove(QgsLayoutPoint(15, 195, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(legend)
scalebar = QgsLayoutItemScaleBar(layout)
scalebar.setStyle("Single Box")
scalebar.setLinkedMap(map_item)
scalebar.applyDefaultSize()
scalebar.attemptMove(QgsLayoutPoint(100, 195, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(scalebar)
source_label = QgsLayoutItemLabel(layout)
source_label.setText("Source: CBS Statistics Netherlands, 2024")
source_label.adjustSizeToText()
source_label.attemptMove(QgsLayoutPoint(15, 285, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(source_label)
project.layoutManager().addLayout(layout)
# Step 7: Export
exporter = QgsLayoutExporter(layout)
pdf_settings = QgsLayoutExporter.PdfExportSettings()
pdf_settings.dpi = 300
result = exporter.exportToPdf("/output/population_density.pdf", pdf_settings)
assert result == QgsLayoutExporter.ExportResult.Success---
Example 2: Categorized Land Use Map
Map with categorical symbology showing distinct land use types.
from qgis.core import (
QgsProject, QgsVectorLayer, QgsCoordinateReferenceSystem,
QgsCategorizedSymbolRenderer, QgsRendererCategory, QgsFillSymbol,
QgsPrintLayout, QgsLayoutItemMap, QgsLayoutItemLabel,
QgsLayoutItemLegend, QgsLayoutItemScaleBar, QgsLayoutItemPicture,
QgsLayoutSize, QgsLayoutPoint, QgsUnitTypes, QgsLayoutExporter
)
from qgis.PyQt.QtGui import QFont
project = QgsProject.instance()
layer = QgsVectorLayer("/data/landuse.shp", "Land Use", "ogr")
assert layer.isValid()
project.addMapLayer(layer)
project.setCrs(QgsCoordinateReferenceSystem("EPSG:32632"))
# Categorized renderer with qualitative colors
categories = [
('residential', '#e41a1c', 'Residential'),
('commercial', '#377eb8', 'Commercial'),
('industrial', '#984ea3', 'Industrial'),
('agricultural', '#4daf4a', 'Agricultural'),
('forest', '#006d2c', 'Forest'),
('water', '#74add1', 'Water'),
('recreation', '#ff7f00', 'Recreation'),
]
renderer = QgsCategorizedSymbolRenderer()
renderer.setClassAttribute('landuse_type')
for value, color, label in categories:
symbol = QgsFillSymbol.createSimple({
'color': color,
'outline_color': '#333333',
'outline_width': '0.15'
})
renderer.addCategory(QgsRendererCategory(value, symbol, label))
layer.setRenderer(renderer)
layer.triggerRepaint()
# Layout with all cartographic elements
layout = QgsPrintLayout(project)
layout.initializeDefaults()
layout.setName("Land Use Map")
# A3 Landscape
page = layout.pageCollection().page(0)
page.setPageSize(QgsLayoutSize(420, 297, QgsUnitTypes.LayoutMillimeters))
map_item = QgsLayoutItemMap(layout)
map_item.attemptResize(QgsLayoutSize(380, 230, QgsUnitTypes.LayoutMillimeters))
map_item.attemptMove(QgsLayoutPoint(20, 30, QgsUnitTypes.LayoutMillimeters))
map_item.zoomToExtent(layer.extent())
layout.addLayoutItem(map_item)
title = QgsLayoutItemLabel(layout)
title.setText("Land Use Classification")
title.setFont(QFont("Arial", 20))
title.adjustSizeToText()
title.attemptMove(QgsLayoutPoint(20, 8, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(title)
legend = QgsLayoutItemLegend(layout)
legend.setLinkedMap(map_item)
legend.attemptMove(QgsLayoutPoint(20, 265, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(legend)
scalebar = QgsLayoutItemScaleBar(layout)
scalebar.setStyle("Double Box")
scalebar.setLinkedMap(map_item)
scalebar.applyDefaultSize()
scalebar.attemptMove(QgsLayoutPoint(200, 265, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(scalebar)
north_arrow = QgsLayoutItemPicture(layout)
north_arrow.setPicturePath(":/images/sketchy/sketchy-north.svg")
north_arrow.attemptResize(QgsLayoutSize(15, 15, QgsUnitTypes.LayoutMillimeters))
north_arrow.attemptMove(QgsLayoutPoint(390, 30, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(north_arrow)
project.layoutManager().addLayout(layout)
exporter = QgsLayoutExporter(layout)
pdf_settings = QgsLayoutExporter.PdfExportSettings()
pdf_settings.dpi = 300
result = exporter.exportToPdf("/output/landuse_map.pdf", pdf_settings)
assert result == QgsLayoutExporter.ExportResult.Success---
Example 3: Atlas — One Map Per District
Generates a separate PDF for each district using atlas functionality.
from qgis.core import (
QgsProject, QgsVectorLayer, QgsCoordinateReferenceSystem,
QgsFillSymbol, QgsSingleSymbolRenderer,
QgsPrintLayout, QgsLayoutItemMap, QgsLayoutItemLabel,
QgsLayoutItemLegend, QgsLayoutItemScaleBar,
QgsLayoutSize, QgsLayoutPoint, QgsUnitTypes, QgsLayoutExporter
)
project = QgsProject.instance()
# Load district boundaries (coverage layer) and points of interest
districts = QgsVectorLayer("/data/districts.gpkg|layername=districts", "Districts", "ogr")
pois = QgsVectorLayer("/data/pois.gpkg|layername=pois", "Points of Interest", "ogr")
assert districts.isValid() and pois.isValid()
project.addMapLayer(districts)
project.addMapLayer(pois)
project.setCrs(QgsCoordinateReferenceSystem("EPSG:28992"))
# Style the layers
districts.setRenderer(QgsSingleSymbolRenderer(
QgsFillSymbol.createSimple({
'color': '#f0f0f0',
'outline_color': '#333333',
'outline_width': '0.5'
})
))
districts.triggerRepaint()
# Create atlas layout
layout = QgsPrintLayout(project)
layout.initializeDefaults()
layout.setName("District Atlas")
map_item = QgsLayoutItemMap(layout)
map_item.attemptResize(QgsLayoutSize(180, 160, QgsUnitTypes.LayoutMillimeters))
map_item.attemptMove(QgsLayoutPoint(15, 30, QgsUnitTypes.LayoutMillimeters))
map_item.zoomToExtent(districts.extent())
layout.addLayoutItem(map_item)
# Atlas-driven title using expression
title = QgsLayoutItemLabel(layout)
title.setText('[% "district_name" %]') # Expression replaced per atlas feature
title.adjustSizeToText()
title.attemptMove(QgsLayoutPoint(15, 8, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(title)
# Page number label
page_label = QgsLayoutItemLabel(layout)
page_label.setText('Page [% @atlas_featurenumber %] of [% @atlas_totalfeatures %]')
page_label.adjustSizeToText()
page_label.attemptMove(QgsLayoutPoint(15, 285, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(page_label)
scalebar = QgsLayoutItemScaleBar(layout)
scalebar.setStyle("Single Box")
scalebar.setLinkedMap(map_item)
scalebar.applyDefaultSize()
scalebar.attemptMove(QgsLayoutPoint(100, 200, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(scalebar)
# Configure atlas
atlas = layout.atlas()
atlas.setCoverageLayer(districts)
atlas.setEnabled(True)
atlas.setFilenameExpression("'district_' || \"district_name\"")
# Map follows atlas feature
map_item.setAtlasDriven(True)
map_item.setAtlasScalingMode(QgsLayoutItemMap.AtlasScalingMode.Auto)
project.layoutManager().addLayout(layout)
# Export individual PDFs per district
pdf_settings = QgsLayoutExporter.PdfExportSettings()
pdf_settings.dpi = 300
result = QgsLayoutExporter.exportToPdfs(atlas, "/output/atlas/", pdf_settings)
assert result == QgsLayoutExporter.ExportResult.Success---
Example 4: Rule-Based Symbology with Multiple Criteria
Map using rule-based renderer for complex classification logic.
from qgis.core import (
QgsProject, QgsVectorLayer, QgsRuleBasedRenderer,
QgsFillSymbol, QgsCoordinateReferenceSystem
)
project = QgsProject.instance()
layer = QgsVectorLayer("/data/buildings.gpkg", "Buildings", "ogr")
assert layer.isValid()
project.addMapLayer(layer)
# Root rule (catch-all)
root_rule = QgsRuleBasedRenderer.Rule(
QgsFillSymbol.createSimple({'color': '#cccccc', 'outline_color': 'black', 'outline_width': '0.1'})
)
# Rule 1: Large residential buildings
rule1 = QgsRuleBasedRenderer.Rule(
QgsFillSymbol.createSimple({'color': '#e41a1c', 'outline_color': 'black', 'outline_width': '0.2'}),
filterExp='"use" = \'residential\' AND "area_m2" > 200',
label='Large Residential'
)
# Rule 2: Small residential buildings
rule2 = QgsRuleBasedRenderer.Rule(
QgsFillSymbol.createSimple({'color': '#fb9a99', 'outline_color': 'black', 'outline_width': '0.2'}),
filterExp='"use" = \'residential\' AND "area_m2" <= 200',
label='Small Residential'
)
# Rule 3: Commercial buildings
rule3 = QgsRuleBasedRenderer.Rule(
QgsFillSymbol.createSimple({'color': '#377eb8', 'outline_color': 'black', 'outline_width': '0.2'}),
filterExp='"use" = \'commercial\'',
label='Commercial'
)
# Rule 4: Industrial buildings
rule4 = QgsRuleBasedRenderer.Rule(
QgsFillSymbol.createSimple({'color': '#984ea3', 'outline_color': 'black', 'outline_width': '0.2'}),
filterExp='"use" = \'industrial\'',
label='Industrial'
)
root_rule.appendChild(rule1)
root_rule.appendChild(rule2)
root_rule.appendChild(rule3)
root_rule.appendChild(rule4)
renderer = QgsRuleBasedRenderer(root_rule)
layer.setRenderer(renderer)
layer.triggerRepaint()---
Example 5: Multi-Layer Map with Raster Background
Combining raster (DEM hillshade) with vector overlays.
from qgis.core import (
QgsProject, QgsVectorLayer, QgsRasterLayer,
QgsCoordinateReferenceSystem, QgsSingleSymbolRenderer,
QgsLineSymbol, QgsMarkerSymbol, QgsFillSymbol,
QgsPrintLayout, QgsLayoutItemMap, QgsLayoutItemLabel,
QgsLayoutItemLegend, QgsLayoutSize, QgsLayoutPoint,
QgsUnitTypes, QgsLayoutExporter
)
from qgis.PyQt.QtGui import QFont
project = QgsProject.instance()
# Load raster background
hillshade = QgsRasterLayer("/data/hillshade.tif", "Hillshade")
assert hillshade.isValid()
project.addMapLayer(hillshade)
# Load vector layers
roads = QgsVectorLayer("/data/roads.shp", "Roads", "ogr")
cities = QgsVectorLayer("/data/cities.shp", "Cities", "ogr")
boundaries = QgsVectorLayer("/data/boundaries.shp", "Boundaries", "ogr")
assert roads.isValid() and cities.isValid() and boundaries.isValid()
project.addMapLayer(boundaries)
project.addMapLayer(roads)
project.addMapLayer(cities)
project.setCrs(QgsCoordinateReferenceSystem("EPSG:32632"))
# Style layers — order matters: hillshade at bottom, cities on top
boundaries.setRenderer(QgsSingleSymbolRenderer(
QgsFillSymbol.createSimple({
'color': '0,0,0,0', # Transparent fill
'outline_color': '#333333',
'outline_width': '0.8'
})
))
roads.setRenderer(QgsSingleSymbolRenderer(
QgsLineSymbol.createSimple({'color': '#e31a1c', 'width': '0.4'})
))
cities.setRenderer(QgsSingleSymbolRenderer(
QgsMarkerSymbol.createSimple({'name': 'circle', 'color': '#1f78b4', 'size': '3'})
))
for lyr in [boundaries, roads, cities]:
lyr.triggerRepaint()
# Create layout and export
layout = QgsPrintLayout(project)
layout.initializeDefaults()
layout.setName("Terrain Overview")
map_item = QgsLayoutItemMap(layout)
map_item.attemptResize(QgsLayoutSize(180, 150, QgsUnitTypes.LayoutMillimeters))
map_item.attemptMove(QgsLayoutPoint(15, 30, QgsUnitTypes.LayoutMillimeters))
map_item.zoomToExtent(boundaries.extent())
layout.addLayoutItem(map_item)
title = QgsLayoutItemLabel(layout)
title.setText("Terrain Overview with Infrastructure")
title.setFont(QFont("Arial", 14))
title.adjustSizeToText()
title.attemptMove(QgsLayoutPoint(15, 10, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(title)
legend = QgsLayoutItemLegend(layout)
legend.setLinkedMap(map_item)
legend.attemptMove(QgsLayoutPoint(15, 190, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(legend)
project.layoutManager().addLayout(layout)
exporter = QgsLayoutExporter(layout)
img_settings = QgsLayoutExporter.ImageExportSettings()
img_settings.dpi = 150
result = exporter.exportToImage("/output/terrain_overview.png", img_settings)
assert result == QgsLayoutExporter.ExportResult.Success---
Example 6: Template-Based Map Generation
Loading a pre-made layout template and populating it with new data.
from qgis.core import (
QgsProject, QgsVectorLayer, QgsPrintLayout,
QgsReadWriteContext, QgsLayoutExporter
)
from qgis.PyQt.QtXml import QDomDocument
project = QgsProject.instance()
# Load data
layer = QgsVectorLayer("/data/new_dataset.gpkg", "New Data", "ogr")
assert layer.isValid()
project.addMapLayer(layer)
# Load template
with open("/templates/standard_a4.qpt", "r") as f:
template_content = f.read()
doc = QDomDocument()
doc.setContent(template_content)
layout = QgsPrintLayout(project)
layout.readXml(doc.documentElement(), doc, QgsReadWriteContext())
layout.setName("Report from Template")
# Update map extent to new data
for item in layout.items():
from qgis.core import QgsLayoutItemMap
if isinstance(item, QgsLayoutItemMap):
item.zoomToExtent(layer.extent())
break
project.layoutManager().addLayout(layout)
# Export
exporter = QgsLayoutExporter(layout)
pdf_settings = QgsLayoutExporter.PdfExportSettings()
pdf_settings.dpi = 300
result = exporter.exportToPdf("/output/report_from_template.pdf", pdf_settings)
assert result == QgsLayoutExporter.ExportResult.Successqgis-agents-map-generator — Methods Reference
Symbology Classes
QgsMarkerSymbol
QgsMarkerSymbol.createSimple(properties: dict) -> QgsMarkerSymbolCreates a marker symbol from a properties dictionary. Keys: name, color, size, outline_color, outline_width.
Available marker names: circle, square, cross, rectangle, diamond, pentagon, triangle, equilateral_triangle, star, regular_star, arrow, filled_arrowhead, x.
QgsLineSymbol
QgsLineSymbol.createSimple(properties: dict) -> QgsLineSymbolCreates a line symbol. Keys: color, width, line_style (solid, dash, dot, dash dot).
QgsFillSymbol
QgsFillSymbol.createSimple(properties: dict) -> QgsFillSymbolCreates a fill symbol. Keys: color, outline_color, outline_width, style (solid, no, horizontal, vertical, cross).
QgsSymbol (base class)
symbol.symbolLayerCount() -> int
symbol.symbolLayer(index: int) -> QgsSymbolLayer
symbol.symbolLayers() -> list[QgsSymbolLayer]
symbol.setColor(color: QColor) -> None
symbol.color() -> QColor---
Renderer Classes
QgsSingleSymbolRenderer
QgsSingleSymbolRenderer(symbol: QgsSymbol)
renderer.setSymbol(symbol: QgsSymbol) -> None
renderer.symbol() -> QgsSymbolQgsCategorizedSymbolRenderer
QgsCategorizedSymbolRenderer(attrName: str = '', categories: list = [])
renderer.setClassAttribute(attr: str) -> None
renderer.classAttribute() -> str
renderer.addCategory(category: QgsRendererCategory) -> None
renderer.categories() -> list[QgsRendererCategory]
renderer.updateCategorySymbol(index: int, symbol: QgsSymbol) -> None
renderer.updateCategoryLabel(index: int, label: str) -> NoneQgsRendererCategory
QgsRendererCategory(value, symbol: QgsSymbol, label: str, render: bool = True)
category.value() -> QVariant
category.symbol() -> QgsSymbol
category.label() -> strQgsGraduatedSymbolRenderer
QgsGraduatedSymbolRenderer(attrName: str = '', ranges: list = [])
renderer.setClassAttribute(attr: str) -> None
renderer.classAttribute() -> str
renderer.addClassRange(range: QgsRendererRange) -> None
renderer.ranges() -> list[QgsRendererRange]
renderer.setSourceColorRamp(ramp: QgsColorRamp) -> None
renderer.updateRangeSymbol(index: int, symbol: QgsSymbol) -> None
renderer.updateRangeLabel(index: int, label: str) -> None
renderer.updateRangeLowerValue(index: int, value: float) -> None
renderer.updateRangeUpperValue(index: int, value: float) -> NoneQgsRendererRange
QgsRendererRange(range: QgsClassificationRange, symbol: QgsSymbol)
range.lowerValue() -> float
range.upperValue() -> float
range.label() -> str
range.symbol() -> QgsSymbolQgsClassificationRange
QgsClassificationRange(label: str, lower: float, upper: float)QgsRuleBasedRenderer
QgsRuleBasedRenderer(root_rule: QgsRuleBasedRenderer.Rule)
# Rule class
QgsRuleBasedRenderer.Rule(symbol: QgsSymbol, scaleMinDenom: int = 0,
scaleMaxDenom: int = 0, filterExp: str = '',
label: str = '', description: str = '')
rule.appendChild(child: QgsRuleBasedRenderer.Rule) -> None
rule.children() -> list[QgsRuleBasedRenderer.Rule]
rule.filterExpression() -> str
rule.setFilterExpression(exp: str) -> None
rule.label() -> str
rule.symbol() -> QgsSymbol---
Color Ramp Classes
QgsGradientColorRamp
QgsGradientColorRamp(color1: QColor, color2: QColor,
discrete: bool = False, stops: list = [])
ramp.color(value: float) -> QColor # value 0.0-1.0QgsPresetSchemeColorRamp
QgsPresetSchemeColorRamp(colors: list[QColor])QgsStyle (access built-in ramps)
style = QgsStyle.defaultStyle()
style.colorRampNames() -> list[str]
style.colorRamp(name: str) -> QgsColorRamp---
Labeling Classes
QgsPalLayerSettings
settings = QgsPalLayerSettings()
settings.fieldName: str # Field name or expression
settings.isExpression: bool # True if fieldName is an expression
settings.enabled: bool # Enable/disable labeling
settings.drawLabels: bool # Draw labels flag
settings.placement: Qgis.LabelPlacement # Placement mode
settings.setFormat(format: QgsTextFormat) -> None
settings.format() -> QgsTextFormatQgis.LabelPlacement enum values:
AroundPoint— labels placed around point featuresOverPoint— labels placed directly over pointLine— labels follow line directionCurved— labels curved along lineHorizontal— horizontal labels for polygonsFree— free placement for polygonsOrderedPositionsAroundPoint— priority-ordered positions
QgsTextFormat
text_format = QgsTextFormat()
text_format.setSize(size: float) -> None
text_format.size() -> float
text_format.setColor(color: QColor) -> None
text_format.color() -> QColor
text_format.setFont(font: QFont) -> None
text_format.font() -> QFont
text_format.buffer() -> QgsTextBufferSettingsQgsTextBufferSettings
buffer = text_format.buffer()
buffer.setEnabled(enabled: bool) -> None
buffer.setSize(size: float) -> None
buffer.setColor(color: QColor) -> None
buffer.setSizeUnit(unit: Qgis.RenderUnit) -> NoneQgsVectorLayerSimpleLabeling
QgsVectorLayerSimpleLabeling(settings: QgsPalLayerSettings)QgsRuleBasedLabeling
QgsRuleBasedLabeling(root: QgsRuleBasedLabeling.Rule)
QgsRuleBasedLabeling.Rule(settings: QgsPalLayerSettings, scaleMinDenom: int = 0,
scaleMaxDenom: int = 0, filterExp: str = '',
description: str = '')
rule.appendChild(child: QgsRuleBasedLabeling.Rule) -> None
rule.setFilterExpression(exp: str) -> None---
Print Layout Classes
QgsPrintLayout
QgsPrintLayout(project: QgsProject)
layout.initializeDefaults() -> None # CRITICAL: creates default page
layout.setName(name: str) -> None
layout.name() -> str
layout.addLayoutItem(item: QgsLayoutItem) -> None
layout.removeLayoutItem(item: QgsLayoutItem) -> None
layout.pageCollection() -> QgsLayoutPageCollection
layout.atlas() -> QgsLayoutAtlasQgsLayoutItemMap
QgsLayoutItemMap(layout: QgsLayout)
map_item.attemptResize(size: QgsLayoutSize) -> None
map_item.attemptMove(point: QgsLayoutPoint) -> None
map_item.zoomToExtent(extent: QgsRectangle) -> None
map_item.setExtent(extent: QgsRectangle) -> None
map_item.setScale(scale: float) -> None
map_item.scale() -> float
map_item.setCrs(crs: QgsCoordinateReferenceSystem) -> None
map_item.setAtlasDriven(enabled: bool) -> None
map_item.setAtlasScalingMode(mode: QgsLayoutItemMap.AtlasScalingMode) -> None
map_item.setFrameEnabled(enabled: bool) -> NoneQgsLayoutItemLabel
QgsLayoutItemLabel(layout: QgsLayout)
label.setText(text: str) -> None # Supports expressions: [% expr %]
label.adjustSizeToText() -> None
label.setFont(font: QFont) -> None
label.attemptMove(point: QgsLayoutPoint) -> None
label.attemptResize(size: QgsLayoutSize) -> NoneQgsLayoutItemLegend
QgsLayoutItemLegend(layout: QgsLayout)
legend.setLinkedMap(map_item: QgsLayoutItemMap) -> None
legend.attemptMove(point: QgsLayoutPoint) -> None
legend.setAutoUpdateModel(auto: bool) -> None
legend.setTitle(title: str) -> NoneQgsLayoutItemScaleBar
QgsLayoutItemScaleBar(layout: QgsLayout)
scalebar.setStyle(style: str) -> None # "Single Box", "Double Box", "Line Ticks Middle", "Numeric"
scalebar.setLinkedMap(map_item: QgsLayoutItemMap) -> None
scalebar.applyDefaultSize() -> None
scalebar.attemptMove(point: QgsLayoutPoint) -> NoneQgsLayoutItemPicture
QgsLayoutItemPicture(layout: QgsLayout)
picture.setPicturePath(path: str) -> None # SVG or raster image path
picture.attemptResize(size: QgsLayoutSize) -> None
picture.attemptMove(point: QgsLayoutPoint) -> NoneQgsLayoutSize / QgsLayoutPoint
QgsLayoutSize(width: float, height: float, units: QgsUnitTypes.LayoutUnit)
QgsLayoutPoint(x: float, y: float, units: QgsUnitTypes.LayoutUnit)
# Units: QgsUnitTypes.LayoutMillimeters, LayoutCentimeters, LayoutInches, LayoutPointsQgsLayoutItemPage
QgsLayoutItemPage(layout: QgsLayout)
page.setPageSize(size: QgsLayoutSize) -> None
layout.pageCollection().addPage(page) -> None---
Atlas Classes
QgsLayoutAtlas
atlas = layout.atlas()
atlas.setCoverageLayer(layer: QgsVectorLayer) -> None
atlas.setEnabled(enabled: bool) -> None
atlas.setFilenameExpression(expression: str) -> None
atlas.setFilterFeatures(enabled: bool) -> None
atlas.setFilterExpression(expression: str) -> None
atlas.beginRender() -> bool
atlas.next() -> bool
atlas.endRender() -> None
atlas.currentFeatureNumber() -> int
atlas.nameForPage(page: int) -> str
atlas.count() -> int---
Export Classes
QgsLayoutExporter
QgsLayoutExporter(layout: QgsLayout)
exporter.exportToPdf(path: str, settings: PdfExportSettings) -> ExportResult
exporter.exportToImage(path: str, settings: ImageExportSettings) -> ExportResult
exporter.exportToSvg(path: str, settings: SvgExportSettings) -> ExportResult
# Static method for atlas export
QgsLayoutExporter.exportToPdfs(atlas: QgsLayoutAtlas, baseDir: str,
settings: PdfExportSettings) -> ExportResultExport Settings
# PDF
pdf_settings = QgsLayoutExporter.PdfExportSettings()
pdf_settings.dpi: float = 300
pdf_settings.forceVectorOutput: bool = False
pdf_settings.appendGeoreference: bool = True
# Image
img_settings = QgsLayoutExporter.ImageExportSettings()
img_settings.dpi: float = 300
img_settings.generateWorldFile: bool = False
# SVG
svg_settings = QgsLayoutExporter.SvgExportSettings()
svg_settings.dpi: float = 300
svg_settings.forceVectorOutput: bool = FalseExportResult Enum
QgsLayoutExporter.ExportResult.Success # 0
QgsLayoutExporter.ExportResult.Canceled # 1
QgsLayoutExporter.ExportResult.MemoryError # 2
QgsLayoutExporter.ExportResult.FileError # 3
QgsLayoutExporter.ExportResult.PrintError # 4
QgsLayoutExporter.ExportResult.SvgLayerError # 5
QgsLayoutExporter.ExportResult.IteratorError # 6---
Template I/O
Save/Load Layout Templates
from qgis.core import QgsReadWriteContext
from qgis.PyQt.QtXml import QDomDocument
# Save
doc = QDomDocument()
layout.writeXml(doc, QgsReadWriteContext())
with open(path, "w") as f:
f.write(doc.toString())
# Load
doc = QDomDocument()
doc.setContent(content_str)
new_layout = QgsPrintLayout(project)
new_layout.readXml(doc.documentElement(), doc, QgsReadWriteContext())