PyQGIS开发-使用 QGIS 创建仪表板样式的地图布局

本文介绍了如何利用QGIS、Python的Pandas和Matplotlib库创建数据驱动的地图。首先,通过QGIS创建布局模板,然后准备工作区目录,包括数据和必要的库。接着,读取数据并将其加载到QGIS画布,处理数据并生成图表。最后,将图表和地图整合到布局中,导出为PDF文件。教程适合已有QGIS基础并了解Python的用户。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

创建数据驱动的地图并不难,QGIS 可以轻松帮助您创建它。 QGIS 有很多很棒的功能可以从各种数据源创建好的地图。 您可以将图表、图像、文本作为附加元素与布局中的地图一起添加,以丰富您的地图,使其具有仪表板元素。

1、解决方法

QGIS 支持 python 脚本来扩展其核心功能。 它给了我们很多优势。 Python 易于使用,有支持性的社区,它有数百个不同的库,这些库在节省执行图像处理、数据可视化、机器学习等特定任务的时间方面非常有用。

在我们的例子中,我们将使用 python 库来处理表格数据并创建图表,这些图表是 Pandas 和 Matplotlib 以及 PyQGIS 本身来访问 QGIS 中的核心功能。 Python 需要自动化整个过程,从读取数据源、过滤和操作数据、创建图表、将它们添加到布局,最后导出到 PDF 文件。

我假设您已经熟悉 QGIS 并且具备非常基本的 Python 编程知识,可以按照本教程进行操作。

2、数据

对于本教程,我只需要两个图层:作为主题图层的动态数据和底图图层。

当然,你需要 QGIS,以及一些 python 库:Pandas 和 Matplotlib 要安装在你的计算机上。 我们将在 QGIS 环境中运行这些 python 库。 不幸的是,QGIS 本身并不提供这些库,所以你必须手动安装它们。 如果你需要在 QGIS 环境中安装 python 库的指导,你可以阅读这篇文章。

3、实现过程

(1)创建布局模板

这个布局模板很像容器,用于安排信息 如图表、地图、标签值 将被显示。 它的布局组成将帮助我们稍后在编写 python 脚本时定义正确的位置来绘制布局信息。

QGIS 布局模板

(2)准备工作区目录

创建目录以组织本教程的输入和输出文件。

D:\PLAYGROUND\MAP-DASHBOARD
|   create_map.py
|   LICENSE
|   README.md
|   utils.py
|
+---data
|       Carto-Voyager.xml
|       earthquakes_2019.csv
|       earthquakes_2019.csvt
|       style_gempa.qml
|
+---img
|       pyqgis.svg
|       report_template_A4.qpt
|       usgs-logo.jpg
|
\---report

(3)读取数据并将其加载到画布

这部分是关于导入所需的库、定义输入和输出数据、读取数据并加载到画布以及将预定义样式应用于图层。

import pandas as pd
import datetime as dt
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import matplotlib as mpl
import time
  • 定义输入和输出

path = “D:\playground\map-dashboard”
file_basemap = os.path.join(path,”data\Carto-Voyager.xml”)
file_csv = os.path.join(path,”data\earthquakes_2019.csv”)
style_layer_gempa = os.path.join(path,”data\style_gempa.qml”)
qpt_path = os.path.join(path,”img/report_template_A4.qpt”)
output_pdf = os.path.join(path,”report/report_A4.pdf”)
#CRS definition
wgs84 = QgsCoordinateReferenceSystem(4326)
  • 加载数据到 QGIS 画布

#Add layer to canvas
layer_basemap = iface.addRasterLayer(file_basemap, "", "gdal")
layer_gempa = iface.addVectorLayer(file_csv, "csv", "ogr")
layer_gempa.setCrs(wgs84, True)
#apply style to layer gempa
layer_gempa.loadNamedStyle(style_layer_gempa)
layer_gempa.triggerRepaint()

(4)数据处理和图表生成

#Create Pandas DataFrame for statistics
df = pd.read_csv(file_csv,sep=';')
df['datetime'] = pd.to_datetime(df['time'], format='%Y-%m-%dT%H:%M:%S.%fZ') #convert string as datetime format
df2019 = df[(df['datetime']>dt.date(2019,1,1)) & (df['datetime']<dt.date(2019,12,31))]  #filter datetime

#stats summary
max_mag = df2019['mag'].max()
max_depth = df2019['depth'].max()
min_depth = df2019['depth'].min()
avg_depth = df2019['depth'].mean()
count_eq = len(df2019.index)

#Modify dataframe for chart
df2019['month'] = df2019['datetime'].dt.strftime('%Y-%m') #add column month
dfEq = pd.pivot_table(df2019, index=['month'], values=["mag"], aggfunc='count',fill_value=0) #number of eq per month
plt.bar(dfEq.index, dfEq['mag'], label = 'Count', color='#22e4de')
#remove lines axes and box
plt.box(False)
#plt.grid(axis='y')
fig = plt.gcf()
#save chart to image file
chart_count_mag = os.path.join(path,"img/chart_count_mag.jpg")
fig.set_size_inches(12, 1.7)
fig.savefig(chart_count_mag, dpi=300, bbox_inches = "tight", facecolor='#f4f4f4')
plt.close(fig)

color = [str(item/255.) for item in df2019['depth']]
area = [2**n for n in df2019['mag'] ]
plt.scatter(df2019['datetime'], df2019['depth'], s=area, c=color, alpha=3/4)
#remove lines axes and box
plt.box(False)
plt.grid(axis='y')
fig = plt.gcf()
plt.gca().invert_yaxis()

#save chart to image file
fig.set_size_inches(12, 1.7)
chart_avg_depth = os.path.join(path,'img/chart_avg_depth.jpg')
fig.savefig(chart_avg_depth, dpi=300, bbox_inches = "tight", facecolor='#f4f4f4')
plt.close(fig)

我们需要将 csv 文件转换为 pandas 数据框。 Pandas真的很强大,我们会得到更多pandas特性的优势来处理原始数据表。 它还擅长处理大数据。

该图表将根据 pandas 数据框中的数据生成。

(5)加载模板并打印到布局

###LAYOUT COMPOSING
document = QDomDocument()
project = QgsProject.instance()
composition = QgsPrintLayout(project)

layout = QgsLayout(project)
layout.initializeDefaults()
# read template content
# read template content
template_file = open(qpt_path)
#template_content = template_file.read()
#template_file.close()
document.setContent(template_content)
items, ok = layout.loadFromTemplate(document, QgsReadWriteContext(), False)

# load layout from template and add to Layout Manager
composition.loadFromTemplate(document, QgsReadWriteContext())
project.layoutManager().addLayout(composition)
layout = project.layoutManager().layoutByName("Report A4")
#add map to layout
map = QgsLayoutItemMap(layout)
map.setRect(20, 20, 20, 20)

#get extent from layer gempa
ext = layer_gempa.extent()
map.setExtent(ext)
layout.addLayoutItem(map)
map.setFrameStrokeWidth(QgsLayoutMeasurement(0.2,QgsUnitTypes.LayoutMillimeters))
map.attemptMove(QgsLayoutPoint(9.275, 22, QgsUnitTypes.LayoutMillimeters))
map.attemptResize(QgsLayoutSize(191.118, 88, QgsUnitTypes.LayoutMillimeters))
scale = map.scale()

# call functions in utils
sys.path.append(path)
from utils import *

# add label max_mag, avg_depth, count_eq
addLabel(layout, str(max_mag), 'Arial', 36, QFont.Bold, False, '#21908d', 0,0, 28.852, 125) #Magnitude  label
addLabel(layout, str(round(avg_depth,2)), 'Arial', 36, QFont.Bold, False, '#21908d', 0,0, 93, 125) #Depth  label
addLabel(layout, str(count_eq), 'Arial', 36, QFont.Bold, False, '#21908d', 0,0, 156, 125) #Magnitude  label

# add chart 1
addImage(layout,chart_count_mag,10, 175, 190, 34) #chart1: donut chart dumping point
addImage(layout,chart_avg_depth,10, 237, 190, 34) #chart1: donut chart dumping point


# export layout to file 
# creats a QgsLayoutExporter object
exporter = QgsLayoutExporter(layout)
settings = exporter.PdfExportSettings()
settings.rasterizeWholeImage = False
#this exports a pdf of the layout object
exporter.exportToPdf(output_pdf, settings)
exporter.exportToImage('D:/playground/map-dashboard/report/report_A4.png', QgsLayoutExporter.ImageExportSettings())

打开 QGIS 并打开 Python 控制台面板或使用快捷键 (Ctrl + Alt + P)。 单击打开脚本按钮以加载您刚刚创建的 python 脚本,然后运行它,就可以得到上面类似仪表盘的布局。

后续考虑把完整资料放出来:https://github.com/gwisnu/map-dashboard

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倾城一少

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值