資料表連接 (PyQGIS)

警告

This tutorial is now obsolete. The preferred way to do table joins via pyqgis is to run the native:joinattributestable algorithm via Python. See details at Running Processing Algorithms via Python (QGIS3).

本教學示範如何在 QGIS 中利用 Python 腳本 (PyQGIS) 操作資料表連接,並為輸出的圖層進行漸層樣式設定。我們要重複一次在 資料表連接 中進行的步驟,但這一次會只使用 python 腳本來操作。

內容說明

請參考 資料表連接 的教學說明。

你還會學到這些

  • 利用 Python 載入壓縮的圖層到 QGIS 中

  • 使用 QgsGraduatedSymbolRendererV2 為向量圖層設定漸層樣式

取得資料

請下載以下資料至電腦中:

tl_2013_06_tract.zip

ca_tracts_pop.csv

ca_tracts_pop.csvt

資料來源 [TIGER] [USCENSUS]

操作流程

你可以在 Python 主控台 或是 QGIS 內建的 編輯器 中輸入以下指令。

  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/1201.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/2165.png
  1. 開始進行資料表連接。在 QGIS 中此操作要使用 QgsVectorJoinInfo 物件,而且我們需要指定 CSV 圖層中的 GEO.id2 作為 連結欄位,以及 shapefile 圖層中的 GEOID 作為 目標欄位。執行下列程式碼後,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/3104.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/467.png
  1. 在本教學剩餘的部分中,我們會繼續使用第一種利用 QgsVectorJoinInfo 的方法。接下來我們要來為連接後的圖層設定漸層樣式。在連接後的圖層中,人口的欄位是 ca_tracts_pop_D001,我們要使用 QgsGraduatedSymbolRendererV2,在 分位數 模式下設定漸層樣式,相關的顏色和數值範圍設定請參考 資料表連接

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/561.png
  1. 在 Python 主控台中直接輸入程式碼,對於執行小型的工作非常方便,不過對於以上的程式片段,使用內建的 編輯器 會容易得多。你可以複製整段程式碼然後貼上到 編輯器 中,然後按下 執行,當腳本執行完畢後,資料表連接和樣式設定就完成了,不需要多餘的手動操作。

../_images/659.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)

If you want to give feedback or share your experience with this tutorial, please comment below. (requires GitHub account)