PyQGIS开发 -- 矢量图层渲染学习笔记

前言

在 GIS 领域中,地图渲染是一个非常重要的特点,各式各样的专题地图能直观地表达地理信息要素丰富的数据信息。PyQGIS 开发中,图层渲染有一套强大的 API 体系,本文就向大家介绍一些常用的图层渲染方法,帮助大家开发自己的专题图软件。

1. 原理

矢量图层渲染最重要的一个类是 QgsFeatureRendererV2,它为图层分配不同的渲染器,实现不同的渲染效果。每一个显示在地图窗口中的矢量图层都有一个 QgsFeatureRendererV2 类型的对象,通过下面的代码就可以获取:

renderer=layer.rendererV2()

QgsFeatureRendererV2 是一个抽象类,通过上面的代码获取到的是它的某个特定子类。它的每一个子类都对应着一个不同的渲染方式,来看看它都有哪些子类:

PyQGIS开发 -- 矢量图层渲染学习笔记_第1张图片

渲染器规定了图层的渲染方式,具体使用哪种符号进行渲染则是通过 QgsSymbolV2 类来决定的。通过

layer.rendererV2().symbols()

可以获取到一个 QgsSymbolV2List() 的对象,也就是该渲染器的符号样式了,它是 QList 类型,注意它样式是一个数组,也就是说同一个要素的样式可以是多种样式类型的叠加(比如已经将点要素渲染成了飞机的图形,但是还想在上面加一个飞机品牌的图标,就可以通过叠加两个样式类型来实现)。本文中我们暂时不考虑多个符号叠加的问题,先来了解一下基本的 QgsSymbolV2 以及 QgsFeatureRendererV2 的一些基本使用方法。

2. 符号类型

2.1 QgsSymbolV2

PyQGIS开发 -- 矢量图层渲染学习笔记_第2张图片

QgsSymbolV2 分为三种样式类型,分别对应“点”、“线”、“面”三种空间要素形态,这三种样式类型是:QgsFillSymbolV2、QgsLineSymbolV2、QgsMarkerSymbolV2 。其余复杂的类型还可以通过组合这三种样式来实现。

3. 渲染方式

对应 QgsFeatureRendererV2 类的每一个子类,可选的渲染方式包括:

  • Single Symbol

  • Categorized

  • Graduated

  • Rule-based

  • Point displacement (仅限“点”要素)

  • Heatmap (仅限“点”要素)

  • Inverted polygons (仅限“面”要素)

下面分章节一个个介绍。

3.1 Single Symbol

简单符号样式,最常见的图层渲染类型,也是加载一个图层之后 QGIS 默认使用的渲染方式,图层使用 QgsSingleSymbolRendererV2 类型渲染器,要将图层设置为该渲染器也比较容易,见如下示例:

# 创建一个点样式
marker_props = {}
marker_props["color"] = 'red'
marker_props["color_border"] = 'black'
marker_props["name"] = 'star'
marker_props["size"] = '3'
marker = QgsMarkerSymbolV2.createSimple(marker_props)

# 更改渲染器的符号样式
renderer = QgsSingleSymbolRendererV2(marker)
layer.setRendererV2(renderer)
layer.triggerRepaint()

“线”图层就用 QgsLineSymbolV2 符号样式,“面”图层就用 QgsFillSymbolV2 符号样式。

3.2 Categorized

分类渲染,即使用图层的某一个字段,将图层中的要素分成不同的类别,每个类别使用不同的符号样式来渲染。GIS类别专题图经常使用这种方式来展示,可以看下图的效果:

PyQGIS开发 -- 矢量图层渲染学习笔记_第3张图片

要设置这样的渲染样式,需要先构造一个存储类别信息的容器,并初始化 QgsCategorizedSymbolRendererV2 类型的渲染器,再将该渲染器设置给对应的图层就好了。需要注意的是,初始化渲染器的时候,要设置指定图层类别的字段名。具体见如下示例:

假设我们现在有一个土地利用类别的图层,在它包含的字段 “DN” 中,存储了分别为 "Developed", "Water"以及"Land" 3 中类别信息。

# 创建一个类别信息容器
landuse = {
    "0":("yellow", "Developed"),
    "1":("darkcyan", "Water"),
    "2":("green", "Land")
}
categories = []
for terrain, (color, label) in landuse.items():
    sym = QgsSymbolV2.defaultSymbol(layer.geometryType())
    sym.setColor(QColor(color))
    category = QgsRendererCategoryV2(terrain, sym, label)
    categories.append(category)

# 指定用于分类的字段名
field = "DN"

# 初始化渲染器,并赋给图层
renderer = QgsCategorizedSymbolRendererV2(field, categories)
layer.setRendererV2(renderer)
layer.triggerRepaint()

注意上面的例子使用了 “QgsSymbolV2.defaultSymbol(layer.geometryType())”这个方法来构造 symbol,这是为了对应不同空间要素图层类型,得到不同的 QgsSymbol 对象。如果是“点”类型图层,那么该方法就返回 QgsMarkerSymbol,“线”类型就返回 QgsLineSymbol,“面”类型就返回 QgsFillSymbol。

3.3 Graduated

渐变渲染也就是将一个要素的属性进行梯度分割,为每个梯度的要素渲染不同的类型,以此来区分要素之间的不同等级。渲染效果如下图所示:

PyQGIS开发 -- 矢量图层渲染学习笔记_第4张图片

使用这个渲染器的关键就在于等级梯度的划分,需要构造一个 QgsRendererRangeV2 的对象来存储这些等级划分的规则。

实现上图效果的代码如下:

# 构造相应的规则
ranges = []
grade = (("less than 300", 0, 300, "green"),
         ("greater than 300 and less than 1000", 300, 1000, "yellow"),
         ("greater than 1000 and less than 2000", 1000, 2000, "red"))
for label, lower, upper, color in grade:
    sym = QgsSymbolV2.defaultSymbol(layer.geometryType())
    sym.setColor(QColor(color))
    rng = QgsRendererRangeV2(lower, upper, sym, label)
    ranges.append(rng)
# 构造渲染器,这里的第一个参数是指定渲染规则应用的图层字段
renderer = QgsGraduatedSymbolRendererV2("ELEV", ranges)
layer.setRendererV2(renderer)

3.4 Rule-based

其实 Rule-based 与Gradient 非常相似,都是通过控制条件来达到分别渲染不同要素的目的。不同的是,Rule-based 更为灵活,可以指定多个字段共同来构造渲染的条件。比如,利用 QGIS 示例数据中的“airports.shp”图层,可以同时指定“ID”< 20 并且“ELEV”> 300 的要素渲染为绿色,满足某种条件“ID”在 20 到 50 之间并且“ELEV”在 300 到 1000 之间的要素渲染为黄色,“ID”在 50 到 100 之间并且“ELEV”在 1000 到 2000 之间的要素渲染为红色,这样来进行分类渲染达到的效果如下图所示:

PyQGIS开发 -- 矢量图层渲染学习笔记_第5张图片

可以看到,并没有红色的要素出现,那是因为这个图层中并没有满足“ID”在 50 到 100 之间并且“ELEV”在 1000 到 2000 之间的要素,但并不妨碍我们这么设置渲染条件。另外,虽然并没有设置青色,但是图中出现了青色的点,其实是因为这个颜色是默认的渲染颜色,当所有规则都不满足的时候,要素可以使用默认颜色来渲染,默认颜色是随机的,当然也可以设置不显示。下图是 QGIS 中样式面板显示的渲染规则:

PyQGIS开发 -- 矢量图层渲染学习笔记_第6张图片

实现这种渲染配置的代码如下:

rootRule = QgsRuleBasedRendererV2.Rule(QgsSymbolV2.defaultSymbol(layer.geometryType()))
rules = (("rule 1", '"ELEV" >= 0 AND "ELEV" <= 300 AND "ID" < 20', "green"),
         ("rule 2", '"ELEV" > 300 AND "ELEV" <= 1000 AND "ID" >= 20 AND "ID" < 50', "yellow"),
         ("rule 3", '"ELEV" > 1000 AND "ELEV" <= 2000 AND "ID" >= 50 AND "ID" < 100', "red"))
for label, exp, color in rules:
    sym = QgsSymbolV2.defaultSymbol(layer.geometryType())
    sym.setColor(QColor(color))
    rule = QgsRuleBasedRendererV2.Rule(sym, 0, 0, exp, label)
    rootRule.appendChild(rule)
renderer = QgsRuleBasedRendererV2(rootRule)
layer.setRendererV2(renderer)
layer.triggerRepaint()

3.5 Point displacement (仅限“点”要素)

这个渲染器可以聚合一些距离比较近的点,用一个中心图形周围附带一圈渲染图形的方式来展示点聚合,当然,必须是“点”要素图层才有这个功能,具体的效果如下面的图所示:

PyQGIS开发 -- 矢量图层渲染学习笔记_第7张图片

缩小的时候

PyQGIS开发 -- 矢量图层渲染学习笔记_第8张图片

适当放大的效果

不难发现,Point displacement 这个渲染样式是可以嵌入其他渲染样式的,比如上面的图其实我们是在 QgsSingleSymbolRendererV2 渲染器的样式上来添加 QgsPointDisplacementRenderer 渲染效果的。也可以指定其他的嵌入样式,作为演示,下面仅展示嵌入基本单一渲染样式的示例:

renderer = QgsPointDisplacementRenderer()
sym = QgsSymbolV2.defaultSymbol(0)
sym.setColor(QColor(255, 0, 0))
renderer.setCenterSymbol(sym)

# 构造一个嵌入的渲染器,这里以 QgsSingleSymbolRendererV2 渲染器作为示例
marker_props = {}
marker_props["color"] = 'green'
marker_props["color_border"] = 'black'
marker_props["name"] = 'star'
marker_props["size"] = '3'
marker = QgsMarkerSymbolV2.createSimple(marker_props)
embededRenderer = QgsSingleSymbolRendererV2(marker)

renderer.setEmbeddedRenderer(embededRenderer)
layer.setRendererV2(renderer)

3.6 Heatmap (仅限“点”要素)

“热力图”用于表现数据点的密度非常有效,相信大家也经常看到下面这样的图:

PyQGIS开发 -- 矢量图层渲染学习笔记_第9张图片

上面这个图是我用 QGIS 示例数据“airports.shp”生成的,使用“黄色->红色”的彩色条带展示数据点密度,红色区域为数据点最为密级的区域。

用 PyQGIS 生成这样的图也非常简单,使用 QgsHeatmapRenderer 渲染器,并根据需要配置 QgsVectorColorRampV2 对象就好了,示例代码如下:

# 构造渲染器
render = QgsHeatmapRenderer()

# 构造用于渲染的color ramp
ramp = QgsVectorGradientColorRampV2()
ramp.setColor1(QColor(255, 255, 178))
ramp.setColor2(QColor(189, 0, 38))
ramp.setDiscrete(False)

# 这里需要配置一下彩色条带的过度颜色,这里的配色就是上图的效果
stops = []
stops.append(QgsGradientStop(0.25, QColor(254, 204, 92)))
stops.append(QgsGradientStop(0.5, QColor(253, 141, 60)))
stops.append(QgsGradientStop(0.75, QColor(240, 59, 32)))

ramp.setStops(stops)
render.setColorRamp(ramp)
layer.setRendererV2(render)
layer.triggerRepaint()

3.7 Inverted polygons (仅限“面”要素)

Inverted polygons 顾名思义,就是多边形取反,构造一个现有多边形的互补形状图层。当然,仅限于“面”要素。渲染的效果可以对比下面两张图:

PyQGIS开发 -- 矢量图层渲染学习笔记_第10张图片

数据默认显示

PyQGIS开发 -- 矢量图层渲染学习笔记_第11张图片

使用 Inverted Polygons 渲染后

同样,QgsInvertedPolygonRenderer 这个渲染器也是有一个嵌入的渲染器的,可以嵌入任意支持的渲染器。要实现上面图中的渲染效果,代码示例如下:

# 构造一个嵌入的渲染器
fill_props = {}
fill_props["color"] = 'green'
fill_props["color_border"] = 'black'
fill = QgsFillSymbolV2.createSimple(fill_props)
embededRenderer = QgsSingleSymbolRendererV2(fill)

# 构造 QgsInvertedPolygonRenderer,并赋给多边形图层
renderer = QgsInvertedPolygonRenderer(embededRenderer)
layer.setRendererV2(renderer)

你可能感兴趣的:(Python,GIS与遥感,python,QGIS,PyQGIS)