资料表连接 (PyQGIS)

本教学示范如何在 QGIS 中利用 Python 脚本 (PyQGIS) 操作资料表连接,并为输出的图层进行渐层样式设定。我们要重复一次在:doc:performing_table_joins 中进行的步骤,但这一次会只使用 python 脚本来操作。

内容说明

请参考:doc:performing_table_joins 的教学说明。

你还会学到这些

  • 利用 Python 载入压缩的图层到 QGIS 中
  • 使用 QgsGraduatedSymbolRendererV2 为向量图层设定渐层样式

取得资料

请下载以下资料至电脑中:

tl_2013_06_tract.zip

ca_tracts_pop.csv

ca_tracts_pop.csvt

资料来源 [TIGER] [USCENSUS]

操作流程

你可以在 Python 主控台 或是 QGIS 内建的:guilabel:`Editor`中输入以下指令。

  1. 第一步是载入 shapefile,我们要的档案包含在档名含有 tract.zip 的压缩档中。虽然我们可以解压缩然后载入 shapefile,不过 OGR 提供元(provider,这里就是 QGIS)也可以经由虚拟的档案系统直接载入 shapefile。只要在路径最前端加上``/vsizip/`` 之后,就能够载入 zip 格式的 shapefile。

注解

zip_uri 在 Linux 和 Mac 系统上的前缀是``/vsizip//``(注意多出来的 /)

zip_uri = '/vsizip/C:/Users/Ujaval/Downloads/tl_2013_06_tract.zip'
shp =  QgsVectorLayer(zip_uri, 'tl_2013_06_tract', 'ogr')
QgsMapLayerRegistry.instance().addMapLayer(shp)
../_images/1105.png
  1. 接下来载入 CSV 档。由于 CSV 档不包含任何空间资讯,我们要使用``delimitedtext``做为资料提供元,载入成表格。
csv_uri = 'file:///C:/Users/Ujaval/Downloads/ca_tracts_pop.csv?delimiter=,'
csv = QgsVectorLayer(csv_uri, 'ca_tracts_pop', 'delimitedtext')
QgsMapLayerRegistry.instance().addMapLayer(csv)
../_images/250.png
  1. 开始进行资料表连接。在 QGIS 中此操作要使用 QgsVectorJoinInfo 物件,而且我们需要指定 CSV 图层中的``GEO.id2`` 作为:guilabel:Join Field`以及 shapefile 图层中的 ``GEOID` 作为:guilabel:Target Field。执行下列程序代码后,shapefile 的图层就会多出一个从 CSV 图层连结过来的属性。

注解

当使用 QgsVectorJoinInfo 时,务必要确认两个图层都已载入至 QgsMapLayerRegistry,否则是不会有任何东西被连结的。

shpField='GEOID'
csvField='GEO.id2'
joinObject = QgsVectorJoinInfo()
joinObject.joinLayerId = csv.id()
joinObject.joinFieldName = csvField
joinObject.targetFieldName = shpField
joinObject.memoryCache = True
shp.addJoin(joinObject)
../_images/330.png
  1. 另一个较简单,而且也较为推荐的方法是使用「处理框架」。你可以呼叫``qgis:joinattributestable`` 演算法来创造连接完毕的图层。

注解

我们这边使用的是``processing.runandload()`` 方法,而不是较常见的``processing.runalg()``来执行演算法,这是因为我们想要把执行的结果图层也加到 QGIS 中,使用``processing.runandload()`` 是较方便的选择。

import processing
shpField='GEOID'
csvField='GEO.id2'
result = processing.runandload('qgis:joinattributestable', shp, csv, shpField, csvField, None)
../_images/422.png
  1. 在本教学剩余的部分中,我们会继续使用第一种利用 QgsVectorJoinInfo 的方法。接下来我们要来为连接后的图层设定渐层样式。在连接后的图层中,人口的栏位是``ca_tracts_pop_D001``,我们要使用 QgsGraduatedSymbolRendererV2 在``Quantile``模式下设定渐层样式,相关的颜色和数值范围设定请参考:doc:performing_table_joins
from PyQt4 import QtGui

myColumn = 'ca_tracts_pop_D001 '
myRangeList = []
myOpacity = 1

ranges = []

myMin1 = 0.0
myMax1 = 3157.2
myLabel1 = 'Group 1'
myColor1 = QtGui.QColor('#f7fbff')
ranges.append((myMin1, myMax1, myLabel1, myColor1))

myMin2 = 3157.2
myMax2 = 4019.0
myLabel2 = 'Group 2'
myColor2 = QtGui.QColor('#c7dcef')
ranges.append((myMin2, myMax2, myLabel2, myColor2))

myMin3 = 4019.0
myMax3 = 4865.8
myLabel3 = 'Group 3'
myColor3 = QtGui.QColor('#72b2d7')
ranges.append((myMin3, myMax3, myLabel3, myColor3))

myMin4 = 4865.8
myMax4 = 5996.4
myLabel4 = 'Group 4'
myColor4 = QtGui.QColor('#2878b8')
ranges.append((myMin4, myMax4, myLabel4, myColor4))

myMin5 = 5996.4
myMax5 = 37452.0
myLabel5 = 'Group 5'
myColor5 = QtGui.QColor('#08306b')
ranges.append((myMin5, myMax5, myLabel5, myColor5))

for myMin, myMax, myLabel, myColor in ranges:
  mySymbol = QgsSymbolV2.defaultSymbol(shp.geometryType())
  mySymbol.setColor(myColor)
  mySymbol.setAlpha(myOpacity)
  myRange = QgsRendererRangeV2(myMin, myMax, mySymbol, myLabel)
  myRangeList.append(myRange)

myRenderer = QgsGraduatedSymbolRendererV2('', myRangeList)
myRenderer.setMode(QgsGraduatedSymbolRendererV2.Quantile)
myRenderer.setClassAttribute(myColumn)

shp.setRendererV2(myRenderer)
../_images/523.png
  1. 在 Python 主控台中直接输入程序代码,对于执行小型的工作非常方便,不过对于以上的程序片段,使用内建的 Editor`会容易得多。你可以复制整段程序代码然后贴上到:guilabel:`Editor 中,然后按下:guilabel:Run.当脚本执行完毕后,资料表连接和样式设定就完成了,不需要多余的手动操作。
../_images/622.png

以下放上完整的``join_attributes.py`` 档做为参考。

from PyQt4 import QtGui
zip_uri = '/vsizip/C:/Users/Ujaval/Downloads/tl_2013_06_tract.zip/tl_2013_06_tract.shp'
shp =  QgsVectorLayer(zip_uri, 'tl_2013_06_tract', 'ogr')
QgsMapLayerRegistry.instance().addMapLayer(shp)

csv_uri = "file:///C:/Users/Ujaval/Downloads/ca_tracts_pop.csv?delimiter=,"
csv = QgsVectorLayer(csv_uri, "ca_tracts_pop", "delimitedtext")
QgsMapLayerRegistry.instance().addMapLayer(csv)

shpField='GEOID'
csvField='GEO.id2'
joinObject = QgsVectorJoinInfo()
joinObject.joinLayerId = csv.id()
joinObject.joinFieldName = csvField
joinObject.targetFieldName = shpField
joinObject.memoryCache = True
shp.addJoin(joinObject)

myColumn = 'ca_tracts_pop_D001 '
myRangeList = []
myOpacity = 1

ranges = []

myMin1 = 0.0
myMax1 = 3157.2
myLabel1 = 'Group 1'
myColor1 = QtGui.QColor('#f7fbff')
ranges.append((myMin1, myMax1, myLabel1, myColor1))

myMin2 = 3157.2
myMax2 = 4019.0
myLabel2 = 'Group 2'
myColor2 = QtGui.QColor('#c7dcef')
ranges.append((myMin2, myMax2, myLabel2, myColor2))

myMin3 = 4019.0
myMax3 = 4865.8
myLabel3 = 'Group 3'
myColor3 = QtGui.QColor('#72b2d7')
ranges.append((myMin3, myMax3, myLabel3, myColor3))

myMin4 = 4865.8
myMax4 = 5996.4
myLabel4 = 'Group 4'
myColor4 = QtGui.QColor('#2878b8')
ranges.append((myMin4, myMax4, myLabel4, myColor4))

myMin5 = 5996.4
myMax5 = 37452.0
myLabel5 = 'Group 5'
myColor5 = QtGui.QColor('#08306b')
ranges.append((myMin5, myMax5, myLabel5, myColor5))

for myMin, myMax, myLabel, myColor in ranges:
    mySymbol = QgsSymbolV2.defaultSymbol(shp.geometryType())
    mySymbol.setColor(myColor)
    mySymbol.setAlpha(myOpacity)
    myRange = QgsRendererRangeV2(myMin, myMax, mySymbol, myLabel)
    myRangeList.append(myRange)

myRenderer = QgsGraduatedSymbolRendererV2('', myRangeList)
myRenderer.setMode(QgsGraduatedSymbolRendererV2.Quantile)
myRenderer.setClassAttribute(myColumn)

shp.setRendererV2(myRenderer)