地图布局与打印

第十一章 地图布局与打印

11.1 打印布局概述

11.1.1 打印布局简介

打印布局(Print Layout)是QGIS中用于创建专业地图输出的工具,支持:

  • 多种地图元素组合
  • 自定义页面尺寸
  • 高质量输出(PDF、图片、SVG)
  • 地图册功能

11.1.2 创建打印布局

创建新布局

项目 > 新建打印布局 (Ctrl+P)
输入布局名称

管理布局

项目 > 布局管理器

11.2 布局界面

11.2.1 界面组成

┌─────────────────────────────────────────────────────────────────┐
│                         菜单栏和工具栏                           │
├────────────────┬─────────────────────────────┬─────────────────┤
│                │                              │                  │
│    元素面板    │        画布区域              │    属性面板      │
│                │                              │                  │
│                │                              │                  │
│                │                              │                  │
└────────────────┴─────────────────────────────┴─────────────────┘

11.2.2 工具栏

工具组 功能
导航工具 缩放、平移画布
添加元素 添加地图、图例、比例尺等
编辑工具 选择、移动、调整元素
对齐工具 元素对齐和分布
地图工具 地图内容交互

11.3 页面设置

11.3.1 页面属性

from qgis.core import QgsLayoutItemPage, QgsLayoutSize, QgsUnitTypes

layout = QgsProject.instance().layoutManager().layoutByName("MyLayout")
page = layout.pageCollection().page(0)

# 设置页面大小
page.setPageSize(QgsLayoutSize(297, 210, QgsUnitTypes.LayoutMillimeters))  # A4横向

# 或使用预设尺寸
page.setPageSize('A3', QgsLayoutItemPage.Landscape)

11.3.2 常用纸张尺寸

纸张 尺寸(mm) 说明
A0 841×1189 大幅面
A1 594×841 大幅面
A2 420×594 中幅面
A3 297×420 中幅面
A4 210×297 标准
Letter 216×279 美国标准
Legal 216×356 美国法律

11.3.3 多页布局

# 添加新页面
layout.pageCollection().addPage(QgsLayoutItemPage(layout))

# 设置新页面属性
new_page = layout.pageCollection().page(1)
new_page.setPageSize('A4', QgsLayoutItemPage.Portrait)

11.4 地图元素

11.4.1 添加地图

from qgis.core import QgsLayoutItemMap

# 创建地图元素
map_item = QgsLayoutItemMap(layout)
map_item.setRect(20, 20, 180, 180)  # x, y, width, height (mm)
map_item.setExtent(iface.mapCanvas().extent())
layout.addLayoutItem(map_item)

11.4.2 地图设置

# 设置比例尺
map_item.setScale(50000)

# 锁定图层
map_item.setLayers([layer1, layer2])
map_item.setKeepLayerSet(True)

# 锁定样式
map_item.setKeepLayerStyles(True)

# 设置CRS
map_item.setCrs(QgsCoordinateReferenceSystem("EPSG:4326"))

# 设置旋转
map_item.setMapRotation(45)

11.4.3 地图网格

from qgis.core import QgsLayoutItemMapGrid

# 创建网格
grid = QgsLayoutItemMapGrid("Grid", map_item)
grid.setEnabled(True)
grid.setIntervalX(10000)  # X间隔
grid.setIntervalY(10000)  # Y间隔
grid.setStyle(QgsLayoutItemMapGrid.Solid)

# 网格标注
grid.setAnnotationEnabled(True)
grid.setAnnotationFormat(QgsLayoutItemMapGrid.DegreeMinuteSecond)

map_item.grids().addGrid(grid)

11.4.4 地图范围指示器

from qgis.core import QgsLayoutItemMapOverview

# 在主地图上显示概览图范围
overview = QgsLayoutItemMapOverview("Overview", map_item)
overview.setLinkedMap(overview_map)
overview.setFrameEnabled(True)
overview.setFrameStrokeColor(QColor(255, 0, 0))

map_item.overviews().addOverview(overview)

11.5 图例

11.5.1 添加图例

from qgis.core import QgsLayoutItemLegend

legend = QgsLayoutItemLegend(layout)
legend.setTitle("图例")
legend.setLinkedMap(map_item)
legend.attemptMove(QgsLayoutPoint(210, 20, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(legend)

11.5.2 图例设置

# 自动更新
legend.setAutoUpdateModel(True)

# 手动控制图层
legend.setAutoUpdateModel(False)
legend.model().setLayerSet([layer1, layer2])

# 分列
legend.setColumnCount(2)

# 样式设置
legend.setStyle(QgsLegendStyle.Title, style)
legend.setFontColor(QColor(0, 0, 0))

# 背景
legend.setBackgroundEnabled(True)
legend.setBackgroundColor(QColor(255, 255, 255))

11.5.3 图例项目

from qgis.core import QgsLegendRenderer

# 修改图例项目名称
model = legend.model()
root = model.rootGroup()
for child in root.children():
    if child.name() == "old_name":
        child.setName("新名称")

11.6 比例尺

11.6.1 添加比例尺

from qgis.core import QgsLayoutItemScaleBar

scalebar = QgsLayoutItemScaleBar(layout)
scalebar.setStyle('Single Box')
scalebar.setLinkedMap(map_item)
scalebar.setUnits(QgsUnitTypes.DistanceKilometers)
scalebar.setNumberOfSegments(4)
scalebar.setNumberOfSegmentsLeft(2)
scalebar.setUnitsPerSegment(10)  # 每段10公里
layout.addLayoutItem(scalebar)

11.6.2 比例尺样式

可用样式:

  • Single Box(单框)
  • Double Box(双框)
  • Line Ticks Middle(中间刻度线)
  • Line Ticks Down(下刻度线)
  • Line Ticks Up(上刻度线)
  • Numeric(数字)
scalebar.setStyle('Double Box')
scalebar.setHeight(5)  # 高度
scalebar.setLabelBarSpace(2)  # 标注间距

11.7 指北针

11.7.1 添加指北针

from qgis.core import QgsLayoutItemPicture

north_arrow = QgsLayoutItemPicture(layout)
north_arrow.setPicturePath('/path/to/north_arrow.svg')
# 或使用内置图片
north_arrow.setPicturePath(':/images/north_arrows/layout_default_north_arrow.svg')
north_arrow.setLinkedMap(map_item)
north_arrow.attemptResize(QgsLayoutSize(20, 20, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(north_arrow)

11.7.2 内置指北针

QGIS提供多种内置指北针样式,位于:

资源路径: images/north_arrows/

11.8 文字元素

11.8.1 添加标签

from qgis.core import QgsLayoutItemLabel

label = QgsLayoutItemLabel(layout)
label.setText("地图标题")
label.setFont(QFont("Arial", 24, QFont.Bold))
label.adjustSizeToText()
layout.addLayoutItem(label)

11.8.2 HTML内容

label = QgsLayoutItemLabel(layout)
label.setMode(QgsLayoutItemLabel.ModeHtml)
label.setText('''
<h1 style="color: blue;">地图标题</h1>
<p>副标题说明文字</p>
''')

11.8.3 表达式

label = QgsLayoutItemLabel(layout)
label.setText('[% @project_title %]')  # 项目标题
label.setText('[% format_date(now(), \'yyyy-MM-dd\') %]')  # 日期
label.setText('[% @layout_name %]')  # 布局名称

11.9 其他元素

11.9.1 图片

from qgis.core import QgsLayoutItemPicture

picture = QgsLayoutItemPicture(layout)
picture.setPicturePath('/path/to/logo.png')
picture.setResizeMode(QgsLayoutItemPicture.Zoom)
layout.addLayoutItem(picture)

11.9.2 形状

from qgis.core import QgsLayoutItemShape

# 矩形
rect = QgsLayoutItemShape(layout)
rect.setShapeType(QgsLayoutItemShape.Rectangle)
rect.attemptResize(QgsLayoutSize(50, 30, QgsUnitTypes.LayoutMillimeters))
layout.addLayoutItem(rect)

# 椭圆
ellipse = QgsLayoutItemShape(layout)
ellipse.setShapeType(QgsLayoutItemShape.Ellipse)

# 三角形
triangle = QgsLayoutItemShape(layout)
triangle.setShapeType(QgsLayoutItemShape.Triangle)

11.9.3 属性表

from qgis.core import QgsLayoutItemAttributeTable

table = QgsLayoutItemAttributeTable.create(layout)
table.setVectorLayer(layer)
table.setMaximumNumberOfFeatures(20)
table.setDisplayedFields(['name', 'population'])

# 添加到框架
frame = QgsLayoutFrame(layout, table)
table.addFrame(frame)

11.9.4 HTML框架

from qgis.core import QgsLayoutItemHtml

html = QgsLayoutItemHtml(layout)
html.setUrl('https://example.com')
# 或设置内容
html.setContentMode(QgsLayoutItemHtml.ManualHtml)
html.setHtml('<div>HTML内容</div>')

11.10 地图册

11.10.1 启用地图册

from qgis.core import QgsLayoutAtlas

atlas = layout.atlas()
atlas.setEnabled(True)
atlas.setCoverageLayer(coverage_layer)
atlas.setPageNameExpression('"name"')

11.10.2 地图册设置

# 设置要素过滤
atlas.setFilterFeatures(True)
atlas.setFilterExpression('"type" = \'city\'')

# 设置排序
atlas.setSortFeatures(True)
atlas.setSortExpression('"name"')

# 设置文件名
atlas.setFilenameExpression("'map_' || @atlas_featurenumber")

11.10.3 地图册表达式

地图册提供特殊表达式变量:

  • @atlas_feature - 当前要素
  • @atlas_featureid - 要素ID
  • @atlas_featurenumber - 序号
  • @atlas_filename - 文件名
  • @atlas_geometry - 几何
  • @atlas_pagename - 页面名称
  • @atlas_totalfeatures - 总数
label.setText('[%@atlas_featurenumber%] / [%@atlas_totalfeatures%]')

11.11 导出输出

11.11.1 导出为图片

from qgis.core import QgsLayoutExporter

exporter = QgsLayoutExporter(layout)

# 导出PNG
settings = QgsLayoutExporter.ImageExportSettings()
settings.dpi = 300
exporter.exportToImage('/path/to/output.png', settings)

# 导出其他格式
exporter.exportToImage('/path/to/output.jpg', settings)
exporter.exportToImage('/path/to/output.tif', settings)

11.11.2 导出为PDF

settings = QgsLayoutExporter.PdfExportSettings()
settings.dpi = 300
settings.rasterizeWholeImage = False
settings.forceVectorOutput = True
settings.exportMetadata = True

exporter.exportToPdf('/path/to/output.pdf', settings)

11.11.3 导出为SVG

settings = QgsLayoutExporter.SvgExportSettings()
settings.dpi = 300
settings.forceVectorOutput = True

exporter.exportToSvg('/path/to/output.svg', settings)

11.11.4 批量导出地图册

atlas = layout.atlas()

# 导出所有页面为图片
exporter.exportToImage('/path/to/atlas/', QgsLayoutExporter.ImageExportSettings())

# 导出为单个PDF
exporter.exportToPdf('/path/to/atlas.pdf', QgsLayoutExporter.PdfExportSettings())

# 导出为多个PDF
for i in range(atlas.count()):
    atlas.seekTo(i)
    exporter.exportToPdf(f'/path/to/page_{i}.pdf', settings)

11.12 模板管理

11.12.1 保存为模板

# 保存布局为模板
layout.saveAsTemplate('/path/to/template.qpt')

11.12.2 从模板创建

# 从模板创建布局
template_path = '/path/to/template.qpt'
with open(template_path) as f:
    template_content = f.read()

doc = QDomDocument()
doc.setContent(template_content)

layout = QgsPrintLayout(QgsProject.instance())
layout.setName("New from Template")
layout.loadFromTemplate(doc, QgsReadWriteContext())

QgsProject.instance().layoutManager().addLayout(layout)

11.13 小结

本章详细介绍了QGIS打印布局功能:

关键要点

  1. 掌握打印布局的创建和管理
  2. 了解各种地图元素的添加和配置
  3. 熟练使用图例、比例尺、指北针等
  4. 掌握地图册功能批量出图
  5. 了解各种导出格式和设置

打印布局是制作专业地图产品的关键工具。


上一章第10章 空间分析工具

下一章第12章 数据编辑与数字化

posted @ 2026-01-08 14:04  我才是银古  阅读(32)  评论(0)    收藏  举报