第八章 數(shù)據(jù)查詢和選擇 ||| 第十章 獲取GIS數(shù)據(jù)列表和描述信息
我們將在本章中介紹以下幾個案例:
- 游標(biāo)對象(cursor object)概況
- 使用搜索游標(biāo)(SearchCursor)訪問要素類中的要素
- 使用where條件語句篩選記錄
- 使用幾何令牌(Geometry tokens)改進游標(biāo)性能
- 使用插入游標(biāo)(InsertCursor)插入行
- 使用更新游標(biāo)(UpdateCursor)更新行
- 使用更新游標(biāo)(UpdateCursor)刪除行
- 編輯會話中插入行并更新行
- 讀取要素類的幾何信息
引言
什么是游標(biāo)(cursor)?游標(biāo)是包含從要素類或表中獲取的一行或多行數(shù)據(jù)的內(nèi)存對象。每行數(shù)據(jù)包含了數(shù)據(jù)源中每個字段中的屬性以及每個要素的幾何信息。游標(biāo)可對表和要素類的數(shù)據(jù)進行搜索,增加,插入,更新以及刪除。
ArcPy數(shù)據(jù)訪問模塊(arcpy.da
)是ArcGIS10.1新引入的模塊,該模塊包含的方法可迭代游標(biāo)對象中的行。你還可以創(chuàng)建多種形式的游標(biāo)。比如,搜索游標(biāo)用于讀取行數(shù)據(jù)。更新游標(biāo)可用于更新行數(shù)據(jù)以及刪除行,插入游標(biāo)可用于插入新行。
ArcPy數(shù)據(jù)訪問模塊的引入帶來了游標(biāo)性能的提升與改進。ArcGIS10.1版本之前,游標(biāo)的處理速度一直較慢,而現(xiàn)在游標(biāo)的處理性能顯著提升。ESRI的評估顯示搜索游標(biāo)速度提升了30倍,而插入游標(biāo)提升了12倍。除了這些整體性能提升之外,數(shù)據(jù)訪問模塊還提供了一些新的選項來讓程序員提升處理速度。你可以指定返回的字段而不用在游標(biāo)中返回全部字段。這樣就通過減少返回的數(shù)據(jù)量來提高性能。相同的情況還有幾何屬性。傳統(tǒng)的方式是當(dāng)你要訪問要素的幾何屬性時,整個幾何定義都會返回。你現(xiàn)在可以使用幾何令牌(geomtry tokens)返回要素的部分幾何屬性而不是全部。你還可以使用列表和元組來代替行。此外新功能還包括編輯會話功能以及處理版本,域名以及子類型的功能。
arcpy.da
提供了三個游標(biāo)函數(shù)。每個游標(biāo)函數(shù)都會返回一個與該函數(shù)同名的游標(biāo)對象。SearchCursor()
函數(shù)創(chuàng)建一個只讀的搜索游標(biāo)(SearchCursor
)對象,該對象包含了表或要素類中的數(shù)據(jù)。InsertCursor()
函數(shù)創(chuàng)建一個插入游標(biāo)(InsertCursor
)對象,該對象可用于向表或要素類插入行。UpdateCursor()
函數(shù)創(chuàng)建一個更新游標(biāo)(UpdateCursor
)對象,該對象可用于編輯或刪除表和要素類中的數(shù)據(jù)。每一個游標(biāo)對象都提供了訪問游標(biāo)中行數(shù)據(jù)的方法。你可以在下表中看到游標(biāo)函數(shù),游標(biāo)對象以及用法說明之間的關(guān)系:
函數(shù) | 創(chuàng)建的游標(biāo)對象 | 說明 |
---|---|---|
SearchCursor() | SearchCursor | 只讀查看表或要素類數(shù)據(jù) |
InsertCursor() | InsertCursor | 向表或要素類插入行 |
UpdateCursor() | UpdateCursor | 編輯或刪除表和要素類行 |
SearchCursor()
函數(shù)用于返回一個搜索游標(biāo)(SearchCursor
)對象。該對象只能用于迭代返回的行數(shù)據(jù)集,且只有只讀權(quán)限。你不能通過該對象進行插入,刪除和更新操作。一個可選的where
條件語句可用于限制返回的行。
創(chuàng)建了一個游標(biāo)實例后通常需要迭代游標(biāo)中的記錄,尤其是使用搜索游標(biāo)(SearchCursor
)和更新游標(biāo)(UpdateCursor
)時。你需要理解關(guān)于遍歷訪問游標(biāo)記錄方面的幾個特點。游標(biāo)只能向前導(dǎo)航。當(dāng)游標(biāo)創(chuàng)建時,游標(biāo)指針會位于游標(biāo)中第一行記錄上面。首次調(diào)用next()
方法時,指針就會移動到首行。除了調(diào)用next()
方法外,你還可以使用for
循環(huán)語句來處理每一行記錄。首行數(shù)據(jù)需要執(zhí)行的操作完成后,調(diào)用next()
方法指針就會移動到第二行。只要你需要訪問其他行,該過程就會持續(xù)下去。不過,某行數(shù)據(jù)訪問之后,你便不能再返回單獨訪問該行記錄。舉個例子,如果當(dāng)前訪問的是第三行,你就不能通過程序返回到第二行中。如果要想重新訪問第一行和第二行,你就需要調(diào)用reset()
方法或者重新創(chuàng)建游標(biāo)對象重新遍歷。如前所說,游標(biāo)也經(jīng)常使用for
循環(huán)語句來遍歷對象。事實上,這也是迭代游標(biāo)對象更為常用的方式,也是編寫腳本中更為有效的方式。游標(biāo)訪問導(dǎo)航方式如下圖所示:
InsertCursor()
函數(shù)可用于創(chuàng)建插入游標(biāo)(InsertCursor
)對象,該游標(biāo)對象可以通過程序向要素類和表中添加新行。對象調(diào)用insertRow()
方法插入行。你還可以使用游標(biāo)對象的fields
屬性訪問一個包含字段名稱的只讀元組對象。通過游標(biāo)訪問要素類或表時,游標(biāo)鎖會鎖定該要素類或表。腳本在處理完成后需要釋放游標(biāo),這一點非常重要。
UpdateCursor()
函數(shù)可用于創(chuàng)建更新游標(biāo)(UpdateCursor
)對象,該對象可以更新或刪除要素類和表中的行。同插入游標(biāo)的情況一樣,函數(shù)會設(shè)置鎖來鎖定正在編輯或刪除的數(shù)據(jù)。如果游標(biāo)是在Python的with
語句中使用的話,鎖會在數(shù)據(jù)處理完成后自動釋放。自動釋放游標(biāo)鎖的功能并不是一直都有。ArcGIS10.1之前的版本中,游標(biāo)需要使用Python的del
語句來進行手動釋放。一旦創(chuàng)建了更新游標(biāo)(UpdateCursor
)實例,你就可以調(diào)用updateCursor()
方法來更新表或要素類中的記錄,也可以調(diào)用deleteRow()
方法刪除行記錄。
數(shù)據(jù)鎖定的問題需要再說明一下。插入游標(biāo)和更新游標(biāo)必須要在它們引用的數(shù)據(jù)源上設(shè)置鎖。這樣就意味著當(dāng)前情況下其他的應(yīng)用程序不能訪問該數(shù)據(jù)源。鎖是一種避免多個用戶同時更改數(shù)據(jù)進而損壞數(shù)據(jù)的機制。在腳本中調(diào)用insertCursor()
和updateCursor()
方法時,Python就會請求對數(shù)據(jù)設(shè)置鎖。游標(biāo)對象處理完成后必須釋放該鎖,這樣其他的用戶在運行ArcMap或ArcCatalog等程序時能夠訪問這些數(shù)據(jù)源。否則的話,其他程序不能訪問這些數(shù)據(jù)。ArcGIS10.1之前的版本中,游標(biāo)必須通過Python的del
語句來解鎖。類似的情況,ArcMap和ArcCatalog同樣會鎖定正在更新或刪除的數(shù)據(jù)。如果數(shù)據(jù)源已經(jīng)被某一程序鎖定,Python腳本便不能訪問該數(shù)據(jù)。因此,最好是在需要使用插入或更新游標(biāo)的獨立腳本運行之前,先關(guān)閉ArcMap和ArcCatalog。
本章中,我們會介紹用于訪問和編輯表和要素類的游標(biāo)的使用。不過,在ArcGIS10.1之前版本中的許多游標(biāo)的概念仍然適用。
使用搜索游標(biāo)(SearchCursor)訪問要素類中的要素
很多情況下,你只是出于讀取目的來檢索表或要素類中的行數(shù)據(jù)。舉個例子,你可能想要生成一個包含城市中所有價值高于10萬美元的地塊的列表。在這種情況下,你不需要編輯數(shù)據(jù)。你的需求只要通過生成一個滿足一定要求的行數(shù)據(jù)列表就可以。
Getting ready
SearchCursor()
函數(shù)用于返回搜索游標(biāo)(SearchCursor
)對象。該對象僅用于迭代一組返回的只讀行數(shù)據(jù)。搜索游標(biāo)對象中不執(zhí)行插入,刪除以及更新等操作。一個可選的where
條件語句用于限制返回的行。在本案例中,你會學(xué)習(xí)如何使用SearchCursor()
函數(shù)來創(chuàng)建一個搜索游標(biāo)(SearchCursor
)對象。
搜索游標(biāo)(SearchCursor
)對象中包含一個fileds
屬性以及next()
和reset()
方法。fields
屬性是一個元組形式的只讀數(shù)據(jù)結(jié)構(gòu),其包含了從要素類和表中獲取的字段。接下來你會看到多次元組與游標(biāo)一起出現(xiàn)的情況。元組是Python中類似于列表的數(shù)據(jù)結(jié)構(gòu),用于保存一系列數(shù)據(jù)。但是元組和列表還是有一些明顯的區(qū)別。元組定義為包含在括號內(nèi)的一系列值,而列表則定義為包含了方括號內(nèi)的一系列值。元組不同于列表,其長度不能進行伸縮,當(dāng)要求數(shù)據(jù)每次占據(jù)一個指定位置的情況下這會是一件很優(yōu)雅的特點。
How to do it...
按照以下步驟來學(xué)習(xí)如何在一個搜索游標(biāo)(SearchCursor
)對象中訪問表或要素類的行數(shù)據(jù):
1.打開IDLE,打開一個新的腳本窗口。
2.腳本保存為C:\ArcpyBook\Ch9\SearchCursor.py
文件。
3.導(dǎo)入arcpy.da
模塊:
import arcpy.da
4.設(shè)置工作空間路徑:
arcpy.env.workspace = "C:/ArcpyBook/Ch9"
5.使用Python中的with
語句創(chuàng)建一個游標(biāo):
with arcpy.da.SearchCursor("Schools.shp",("Facility","Name")) as cursor:
6.循環(huán)搜索游標(biāo)(SearchCursor
)并打印學(xué)校的名稱。確保for
循環(huán)語句的縮進以位于with
語句塊內(nèi):
for row in sorted(cursor):
print "Shcool name:" + row[1]
7.保存腳本。
8.運行腳本。你會看到以下輸出結(jié)果:
School name: ALLAN
School name: ALLISON
School name: ANDREWS
School name: BARANOFF
School name: BARRINGTON
School name: BARTON CREEK
………………………………
How it works...
與SearchCursor()
函數(shù)一起使用的with
語句將會創(chuàng)建游標(biāo),打開游標(biāo)并關(guān)閉游標(biāo)。因此你就不必像ArcGIS10.1之前版本那樣關(guān)注游標(biāo)鎖的釋放問題。傳遞給SearchCursor()
函數(shù)的第一個參數(shù)是一個要素類,這里指Schools.shp
文件。第二個參數(shù)是一個包含了我們想要返回游標(biāo)中的字段名稱的元組。出于性能考慮,最好控制僅返回游標(biāo)對象中那些你需要用來完成任務(wù)的字段。本案例中,我們僅指定返回Facility
和Name
字段。搜索游標(biāo)(SearchCursor
)對象保存在cursor
變量中。
在with
語句塊中,我們使用了Python的for
循環(huán)語句來循環(huán)返回的每一個學(xué)校數(shù)據(jù)。我們還使用了Python中的sorted()
函數(shù)來對游標(biāo)中的內(nèi)容進行排序。你只要簡單地使用代表你想要返回的字段的索引數(shù)就可以獲取該字段值。在本案例中,我們想要返回Name
列中的內(nèi)容,相對應(yīng)的索引數(shù)為1
,也就說返回的字段名稱元組中的第二個元素項。
使用where條件語句篩選記錄
默認(rèn)情況下,搜索游標(biāo)(SearchCursor
)會包含表或要素類中的所有行。不過很多情況下,你想按照一定的條件來限制返回的行數(shù)。通過使用where
條件語句指定一個篩選器來限制返回到記錄。
Getting ready
當(dāng)你創(chuàng)建一個搜索游標(biāo)(SearchCursor
)對象時,默認(rèn)情況下會返回表或要素類中的所有行。不過很多情況下,你想要限制返回的記錄。你可以在調(diào)用SearchCursor()
函數(shù)時,創(chuàng)建一個查詢條件并傳遞給where
條件語句參數(shù)來實現(xiàn)。在本案例中,你會在上一個案例創(chuàng)建的腳本中添加where
條件語句來限制返回的記錄。
How to do it...
按照以下步驟來對搜索游標(biāo)對象指定一個篩選器來限制從表或要素類中返回的行數(shù)據(jù):
1.打開IDLE,加載在上一個案例中創(chuàng)建的SearchCursor.py
文件。
2.在SearchCursor()
函數(shù)中添加where
語句來查詢Facility
字段中包含文本“HIGH SCHOOL”
的記錄:
with.arcpy.da.SearchCursor("Schools.shp",("Facility","Name"),'"Facility"=\'HIGH SCHOOL\'')as cursor:
3.保存并允許腳本。輸出結(jié)果只有高中學(xué)校返回:
High school name: AKINS
High school name: ALTERNATIVE LEARNING CENTER
High school name: ANDERSON
High school name: AUSTIN
High school name: BOWIE
High school name: CROCKETT
High school name: DEL VALLE
High school name: ELGIN
High school name: GARZA
High school name: HENDRICKSON
High school name: JOHN B CONNALLY
High school name: JOHNSTON
High school name: LAGO VISTA
How it works...
我們在第八章數(shù)據(jù)查詢和選擇中介紹了如何創(chuàng)建查詢語句。where
條件語句參數(shù)接受任何語法正確的SQL語句,在本案例中該參數(shù)用于限制返回的記錄數(shù)。
使用幾何令牌(Geometry tokens)改進游標(biāo)性能
幾何令牌(Geometry tokens)是ArcGIS10.1引入用來改進游標(biāo)性能。使用幾何令牌允許只返回部分幾何信息而不用返回整個幾何對象。由于返回數(shù)據(jù)量的原因,返回要素的完整幾何對象會降低游標(biāo)性能。而僅返回需要的幾何信息則速度明顯快很多。
Getting ready
令牌是以SHAPE@<要返回的要素幾何信息>
的格式作為字段列表中的字段來傳遞給游標(biāo)構(gòu)造函數(shù)。OID@令牌是唯一的例外,該令牌返回要素的對象ID。下面的代碼示例用來訪問要素的質(zhì)心X,Y坐標(biāo):
with.arcpy.da.SearchCursor(fc,("SHAPE@XY","Facility","Name"))as cursor:
下表中列出了可用的幾何令牌。不是所有的游標(biāo)對象支持所有的幾何令牌。請自行查看ArcGIS幫助文件中關(guān)于每類游標(biāo)類型所支持的令牌的相關(guān)內(nèi)容。SHAPE@
幾何令牌返回要素的完整幾何對象。不過使用SHAPE@
需要注意,返回要素的完整幾何對象的性能成本開銷大,能夠顯著地影響性能。如果你不需要完整幾何對象,那就不要使用該令牌!
令牌 | 說明 |
---|---|
SHAPE@ | 要素的幾何對象。 |
SHAPE@XY | 一組要素的質(zhì)心 x,y 坐標(biāo)。 |
SHAPE@TRUECENTROID | 一組要素的真正質(zhì)心 x,y 坐標(biāo)。 |
SHAPE@X | 要素的雙精度 x 坐標(biāo)。 |
SHAPE@Y | 要素的雙精度 y 坐標(biāo)。 |
SHAPE@Z | 要素的雙精度 z 坐標(biāo)。 |
SHAPE@M | 要素的雙精度 m 值。 |
SHAPE@JSON | 表示幾何的 esri JSON 字符串。 |
SHAPE@WKB | OGC 幾何的WKB制圖表達。該存儲類型將幾何值表示為不間斷的字節(jié)流形式。 |
SHAPE@WKT | OGC 幾何的WKT制圖表達。其將幾何值表示為文本字符串。 |
SHAPE@AREA | 要素的雙精度面積。 |
SHAPE@LENGTH | 要素的雙精度長度。 |
在本案例中,將使用幾何令牌來提高游標(biāo)的性能。你將獲取parcels
要素類中每一個地塊的質(zhì)心XY坐標(biāo)以及一些其他屬性信息。
How to do it...
按照以下步驟向游標(biāo)對象中添加幾何令牌,這會提高游標(biāo)對象的執(zhí)行效率:
1.打開IDLE,打開一個新的腳本窗口。
2.保存腳本至C:\ArcpyBook\Ch9\GeometryToken.py
文件。
3.導(dǎo)入arcpy.da
模塊和time
模塊:
import arcpy,time
4.設(shè)置工作空間路徑:
arcpy.env.workspace = "C:/ArcpyBook/Ch9"
5.我們將計算使用幾何令牌的情況下執(zhí)行腳本花費的時間。在腳本中添加一個開始時間:
start = time.clock()
6.使用with
語句來創(chuàng)建一個游標(biāo),該游標(biāo)包含每一個要素的質(zhì)心坐標(biāo)以及存儲在PY_FULL_OW
字段中的所有者信息:
with.arcpy.da.SearchCursor("coa_parcels.shp",("PY_FULL_OW","SHAPE@XY")) as cursor:
7.循環(huán)搜索游標(biāo)(SearchCursor
)的每一行并打印地塊所有者的名字。確保for
循環(huán)語句的縮進以位于with
語句塊內(nèi):
for row in cursor:
print "Parcel owner: {0} has a location of:{1}".format(row[0],row[1])
8.計算運行時間:
elapsed = time.clock()-start
9.打印運行時間:
print "Execution time: " + str(elapsed)
10.保存腳本。
11.運行腳本。你會看到與下面內(nèi)容類似的輸出結(jié)果。注意一些執(zhí)行時間,你的時間會不一樣:
Parcel owner:AUSTIN AFFORDABLE HOUSING has a location of:(3139099.127188288, 10111192.98966641)
...............................................
Parcel owner: CITY OF AUSTIN ATTN REAL ESTATE DIVISION has a location of: (3110480.5197341456, 10070911.174956793)
Parcel owner: CITY OF AUSTIN ATTN REAL ESTATE DIVISION has a location of: (3110670.413783513, 10070800.960865)
Parcel owner: CITY OF AUSTIN has a location of:(3143925.0013213265, 10029388.97419636)
Parcel owner: CITY OF AUSTIN % DOROTHY NELL ANDERSON ATTN BARRY LEE ANDERSON has a location of: (3134432.983822767,10072192.047894118)
Execution time: 59.2429891474
現(xiàn)在,我們計算返回完整幾何對象的的運行時間:
1.另存為腳本至C:\ArcpyBook\Ch9\GeomteryTokenEntireGeometry.py
文件。
2.在SearchCursor()
函數(shù)使用SHAPE@
替換SHAPE@XY
來返回完整幾何信息:
with arcpy.da.SearchCursor("coa_parcels.shp",("PY_FULL_OW","SHAPE@")) as cursor:
3.保存并運行腳本。你會看到下面的輸出結(jié)果。你的時間會跟我的不一樣,不過注意執(zhí)行時間變的慢了一些。在本案例中,由于我們僅返回了2600個元素運行時間只慢了一秒多。如果要素類的數(shù)據(jù)量足夠大,運行時間的差異會加大:
Parcel owner: AUSTIN AFFORDABLE HOUSING has a location of:<geoprocessing describe geometry object object at 0x02ED44C0>
.........................................
Parcel owner: CITY OF AUSTIN ATTN REAL ESTATE DIVISION has a location of: <geoprocessing describe geometry object object at 0x06B9BE00>
Parcel owner: CITY OF AUSTIN ATTN REAL ESTATE DIVISION has a location of: <geoprocessing describe geometry object object at 0x2400A700>
Parcel owner: CITY OF AUSTIN has a location of: <geoprocessing describe geometry object object at 0x06B9BE00>
Parcel owner: CITY OF AUSTIN % DOROTHY NELL ANDERSON ATTN BARRY LEE ANDERSON has a location of: <geoprocessing describe geometry object object at 0x2400A700>
Execution time: 60.0561424156
How it works...
幾何令牌可以作為游標(biāo)構(gòu)造函數(shù)中的一個字段名稱來使用。這些令牌僅返回部分幾何信息而不用返回完整的幾何信息,因此使用幾何令牌用于提升游標(biāo)性能。這將會顯著提升游標(biāo)性能,尤其是處理大數(shù)據(jù)量的線或面數(shù)據(jù)集。如果只需要游標(biāo)對象中的特定的幾何信息,那你應(yīng)該使用幾何令牌。
使用插入游標(biāo)(InsertCursor)插入行
你還可以使用插入游標(biāo)(InsertCursor
)對象向表或要素類中插入行。如果想在新行中插入屬性值,你就需要按照屬性表中字段順序依次賦值。
Getting ready
InsertCursor()
函數(shù)可用于創(chuàng)建插入游標(biāo)(InsertCursor
)對象,該游標(biāo)對象可以通過程序向要素類和表中添加新行。insertRow()
方法可向插入游標(biāo)(InsertCursor
)對象中添加新行。行以列表或元組的形式傳遞給insertRow()
方法。列表中的值需與插入游標(biāo)對象創(chuàng)建時定義的字段值一致。同其他類型的游標(biāo)一樣,你還可以使用該方法中的第二個參數(shù)來限制返回的字段名稱。InsertCursor()
函數(shù)也支持幾何令牌。
下面的代碼示例闡述了如何使用插入游標(biāo)(InsertCursor
)對象向要素類中插入新行。本案例中,我們要在California
要素類中插入兩個新的火情點數(shù)據(jù)。要插入的行數(shù)據(jù)需要保存在一個列表變量中。之后,在構(gòu)造函數(shù)中使用要素類和字段參數(shù)創(chuàng)建一個插入游標(biāo)對象。最后,調(diào)用insertRow()
方法向要素類中插入新行:
rowValue = [('Bastrop','N',3000,(-105.345,32.234)),('Ft Davis','N',456,(-109.456,33.468))]
fc = "C:/data/wildfires.gdb/California"
fileds = ["FIRE_NAME","FIRE_CONTAINED","ACRES","SHAPE@XY"]
with arcpy.da.InsertCursor(fc,fields) as cursor:
for row in rowValues:
cursor.insertCursor(row)
在本案例中,使用插入游標(biāo)將從文本文件中的讀取的火情數(shù)據(jù)添加到一個點要素類中。向要素類中插入行時,你需要清楚如何向要素類中添加要素的幾何表達。這可以通過使用插入游標(biāo)(InsertCursor
)以及兩個重要的對象:數(shù)組(Array)和點(Point)。在本案例中,我們將火情發(fā)生位置點添加到一個當(dāng)空的點要素類中。此外,你還會使用Python的文件操作方法從文本文件中讀取坐標(biāo)數(shù)據(jù)。
How to do it...
我們將導(dǎo)入北美洲地區(qū)發(fā)生在2007年10月份某一天的火情數(shù)據(jù)。數(shù)據(jù)包含在一個以逗號為分隔符的文本文件中,該文件包含了一天內(nèi)發(fā)生的每一次火災(zāi),一次火災(zāi)一行記錄。火災(zāi)數(shù)據(jù)包含了使用逗號分隔符隔開的經(jīng)緯度以及可信度值。該數(shù)據(jù)是使用遙感數(shù)據(jù)自動獲取火災(zāi)的發(fā)生情況。可信度值數(shù)據(jù)范圍從0到100。可信值越高則表示火災(zāi)發(fā)生的可能性越大:
1.打開C:\ArcpyBook\Ch9\WildfireData\NorthAmericaWildfire_2007275.txt
文件查看文件中的內(nèi)容。
你會發(fā)現(xiàn)該文件是一個包含火災(zāi)發(fā)生位置以及可信度值信息的逗號分隔符文件。我們會使用Python來逐行讀取該文件的內(nèi)容并向位于
C:\ArcpyBook\Ch9\WildfireData\WildlandFires.mdb
個人地理數(shù)據(jù)庫中的FireIncidents
要素類中插入新的點要素。
2.關(guān)閉文本文件。
3.打開ArcCatalog。
4.瀏覽至C:\ArcpyBook\Ch9\WildfireData
位置。
你會看到一個叫做WildlandFires
的個人地理數(shù)據(jù)庫。打開該數(shù)據(jù)框就會看到一個叫做FireIncidents
的要素類。當(dāng)前這是一個空的要素類。我們會通過讀取剛才打開的文本文件來添加點要素。
5.右鍵單擊FireIncidents
選擇屬性(Properties)。
6.點擊字段(Fields)選項卡。
我們之前在文件中看到的經(jīng)緯度值會導(dǎo)入SHAPE
字段中而可信度值將寫入到CONFIDENCEVALUE
字段中。
7.打開IDLE并創(chuàng)建一個新腳本。
8.腳本保存為C:\ArcpyBook\Ch9\InsertWildfires.py
文件。
9.導(dǎo)入arcpy
模塊。
import arcpy
10.設(shè)置工作空間路徑:
arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"
11.打開文本文件并讀取所有的行至列表中:
f = open(r"C:\ArcpyBook\Ch9\WildfireData\NorthAmericaWildfire_2007275.txt","r")
lstFires = f.readlines()
12.添加try
語句塊:
try:
13.使用with
語句創(chuàng)建一個插入游標(biāo)(InsertCursor
)對象。確保語句語句以位于try
語句內(nèi)。游標(biāo)會創(chuàng)建在FireIncidents
要素類中:
with arcpy.da.InsertCursor("FireIncidents",("SHAPE@XY","CONFIDENCEVALUE")) as cur:
14.創(chuàng)建一個計數(shù)器變量以用于打印處理進程:
cntr = 1
15.使用for
語句循環(huán)文本文件的行文件。由于文本文件使用逗號分隔符,因此我們使用Python的split()
函數(shù)來將數(shù)值分離并保存至一個列表變量vals
中。之后我們將分別提取緯度,經(jīng)度和可信度值并分別賦值給變量。最后,我們會將這些值放入一個叫做rowValue
的列表變量中,該變量之后傳遞給insertRow()
方法,最后我們將打印消息:
for fire in lstFires:
if 'Latitude' in fire:
continue
vals = fire.split(",")
latitude =float(vals[0])
longitude = float(vals[1])
confid = int(vals[2])
rowValue = [(longitude,latitude),confid]
cur.insertRow(rowValue)
print "Record number " + str(cntr) + " written to feature class"
cntr = cntr + 1
16.添加except
語句,如果發(fā)生錯誤將打印錯誤:
except Exception as e:
print e.message
17.添加finally
語句來關(guān)閉文本文件:
finally:
f.close()
18.完整代碼如下:
import arcpy
arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"
f = open(r"C:\ArcpyBook\Ch9\WildfireData\NorthAmericaWildfire_2007275.txt","r")
lstFires = f.readlines()
try:
with arcpy.da.InsertCursor("FireIncidents",("SHAPE@XY","CONFIDENCEVALUE")) as cur:
cntr = 1
for fire in lstFires:
if "Latitude" in fire:
continue
vals = fire.split(",")
latitude = float(vals[0])
longitude = float(vals[1])
confid = int(vals[2])
rowValue = [(longitude,latitude),confid]
cur.insertRow(rowValue)
print "Record number " + str(cntr) + " written to feature class"
cntr = cntr + 1
except Exception as e:
print e.message
finally:
f.close()
19.保存并運行腳本。隨著腳本的運行,你會看到下面的消息寫入窗口屏幕中:
Record number: 1 written to feature class
.......................................
Record number: 406 written to feature class
Record number: 407 written to feature class
Record number: 408 written to feature class
Record number: 409 written to feature class
Record number: 410 written to feature class
Record number: 411 written to feature class
20.打開ArcMap添加FireIncidents
要素類。點數(shù)據(jù)如下圖所示:
How it works...
這里有必要作進一步解釋。lstFires
變量保存了一個包含逗號分隔符文本文件中所有火情數(shù)據(jù)的列表。for
語句會逐一循環(huán)遍歷每條記錄,將每一個單獨的記錄插入到fire
變量中。我們同樣還包括了一個if
條件語句來跳過文件中的首行記錄,該行記錄用來作為數(shù)據(jù)頭用。如前所述,我們之后會從vals
變量中提取每個單獨的緯度,經(jīng)度和可信度值元素項,其中vals
變量是一個Pyhon列表對象。之后我們將提取的值分別賦值給變量latitude
,longitude
以及confid
。之后我們按照插入游標(biāo)(InsertCursor)創(chuàng)建時定義的字段順序?qū)⑦@些值放入一個叫做rowValue
的列表變量中。即經(jīng)緯度值對放在前面,之后是可信度值。最后,我們對變量cur
調(diào)用insertRow()
方法并將新的rowValue
變量傳遞給該方法。我們打印一條信息來指明腳本執(zhí)行的進程,同時創(chuàng)建except
和finally
語句來處理錯誤并關(guān)閉文本文件。在finally
語句塊中添加f.close()
方法確保即便在前面的try
語句中發(fā)生錯誤,該語句仍會執(zhí)行關(guān)閉文本文件操作。
使用更新游標(biāo)(UpdateCursor)更新行
如果需要編輯或刪除表或要素類中的行數(shù)據(jù),你可以使用更新游標(biāo)(UpdateCursor
)。同插入游標(biāo)(InsertCursor
)一樣,更新游標(biāo)(UpdateCursor
)中的數(shù)據(jù)內(nèi)容可以通過使用where
條件語句來控制。
Getting ready
UpdateCursor()
函數(shù)用于更新或刪除表或要素類中的行數(shù)據(jù)。調(diào)用UpdateCursor()
函數(shù)將返回一個更新游標(biāo)(UpdateCursor
)對象。
更新游標(biāo)(UpdateCursor
)對象會在正在編輯或刪除的數(shù)據(jù)上設(shè)置鎖。如果游標(biāo)是在Python的with
語句中使用的話,該鎖會在數(shù)據(jù)處理完成后自動釋放。游標(biāo)鎖自動釋放的功能并不是一直都有。之前的版本中,游標(biāo)需要使用Python的del
語句來進行手動釋放。創(chuàng)建了更新游標(biāo)(UpdateCursor
)實例,你就可以調(diào)用updateRow()
方法來更新表或要素類中的記錄,也可以調(diào)用deleteRow()
方法刪除行記錄。
本案例中,我們將會在腳本中使用更新游標(biāo)(UpdateCursor
)來更新FireIncidents
要素類中的每一個要素,我們會添加一個對可信度值描述性更強的字段并賦值poor
,fair
,good
或excellent
。更新字段值之前,腳本會先向FireIncidents
要素類中添加一個新字段。
How to do it...
按照以下步驟來創(chuàng)建一個更新游標(biāo)(UpdateCursor
)對象來編輯要素類中的行數(shù)據(jù):
1.打開IDLE并創(chuàng)建一個新腳本。
2.腳本保存為C:\ArcpyBook\Ch9\UpdateWildfires.py
文件。
3.導(dǎo)入arcpy
模塊。
import arcpy
4.設(shè)置工作空間路徑:
arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"
5.添加try
語句塊:
try:
6.在FireIncidents
要素類中添加一個CONFID_RATING
的新字段。確保語句縮進以位于try
語句中:
arcpy.AddField_management("FireIncidents","CONFID_RATING","TEXT",10)
print "CONFID_RATING field added to FireIncidents"
7.在with
語句中創(chuàng)建一個更新游標(biāo)(UpdateCursor
)的實例:
with arcpy.da.UpdateCursor("FireIncidents",("CONFIDENCEVALUE","CONFID_RATING")) as cursor:
8.創(chuàng)建一個計數(shù)器變量用于打印處理進程。確保語句的縮進以位于with
語句塊中:
cntr = 1
9.循環(huán)遍歷FireIncidents
要素類中每行數(shù)據(jù)。按照以下原則更新CONFID_RATING
字段值:
可信值在0至40之間賦值
POOR
可信值在41至60之間賦值FAIR
可信值在61至85之間賦值GOOD
可信值在86至100之間賦值EXCELLENT
for row in cursor:
if row[0] <= 40:
row[1] = 'POOR'
elif row[0] > 40 and row[0] <= 60:
row[1] = 'FAIR'
elif row[0] > 61 and row[0] <= 85:
row[1] = 'GOOD'
else:
row[1] = 'EXCELLENT'
cursor.updateRow(row)
print "Record number " + str(cntr) + " updated"
cntr = cntr + 1
10.添加except
語句塊,發(fā)生錯誤時打印錯誤消息:
except Exception as e:
print e.message
11.完整代碼如下:
import arcpy
arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"
try:
arcpy.AddField_management("FireIncidents","CONFID_RATING","TEXT","10")
print "CONFID_RATING field added to FireIncidents"
with arcpy.da.UpdateCursor("FireIncidents",("CONFIDENCEVALUE","CONFID_RATING")) as cursor:
cntr = 1
for row in cursor:
if row[0] <= 40:
row[1] = 'POOR'
elif row[0] > 40 and row[0] <= 60:
row[1] = 'FAIR'
elif row[0] > 60 and row[0] <=85:
row[1] = 'GOOD'
else:
row[1] = 'EXCELLENT'
cursor.updateRow(row)
print "Record number " + str(cntr) + " updated"
cntr = cntr + 1
except Exception as e:
print e.message
12.保存并運行腳本。隨著腳本的運行,你會看到下面的消息寫入窗口屏幕中:
CONFID_RATING field added to FireIncidents
Record number 1 updated
..................
Record number 406 updated
Record number 407 updated
Record number 408 updated
Record number 409 updated
Record number 410 updated
13.打開ArcMap,添加FireIncidents
要素類數(shù)據(jù)。打開屬性表你就會看到一個新的CONFID_RATING
字段,且已經(jīng)通過更新游標(biāo)(UpdateCursor
)生成了屬性值:
你在非編輯會話狀態(tài)下對游標(biāo)對象中所執(zhí)行的插入,更新和刪除操作是不能恢復(fù)的。不過,ArcGIS10.1支持編輯會話狀態(tài)下的游標(biāo)功能,也就意味著你可以在編輯狀態(tài)下完成這些操作來避免不能恢復(fù)的問題。我們會在后面介紹編輯會話相關(guān)內(nèi)容。
How it works...
本案例中,我們使用更新游標(biāo)(UpdateCursor
)來更新了要素類中的所有要素。首先我們使用Add Field工具添加一個CONFID_RATING
字段,該字段用于保存我們根據(jù)其他字段值來賦的新值。根據(jù)CONFIDENCEVALUE
字段值分成差(poor),中(fair),好(good),優(yōu)(excellent)四個級別。之后基于FireIncidents
要素類創(chuàng)建了一個更新游標(biāo)(UpdateCursor
)實例,并返回了之前提及的兩個字段。隨后腳本循環(huán)遍歷每一個要素并根據(jù)CONFIDENCEVALUE
字段值在CONFID_RATING
字段賦值差(poor),中(fair),好(good)或優(yōu)(excellent)。Python的if/elif/else
結(jié)構(gòu)用來控制根據(jù)可信度值賦值的處理流程。CONFID_RATING
的值之后通過updateRow()
方法更新到要素類中。
使用更新游標(biāo)(UpdateCursor)刪除行
更新游標(biāo)(UpdateCursor
)除了用于編輯表或要素類中的行,還可以刪除行。需要注意一點,非編輯會話狀態(tài)下的刪除行操作是不可恢復(fù)的。
Getting ready
更新游標(biāo)(UpdateCursor
)除了可以更新記錄,還可以刪除表或要素類中的行。更新行和刪除行操作中,創(chuàng)建更新游標(biāo)(UpdateCursor
)的方式都是相同的,不過刪除行操作不調(diào)用updateRow()
方法,而是調(diào)用deleteRow()
方法。你也可以使用where
條件語句來限制返回的記錄。在本案例中,我們將使用一個通過where
條件語句篩選的更新游標(biāo)(UpdateCursor
)來刪除FireIncidents
要素類中的記錄。
How to do it...
按照以下步驟創(chuàng)建一個更新游標(biāo)(UpdateCursor
)來刪除要素類中的行:
1.打開IDLE并創(chuàng)建一個新腳本。
2.腳本保存為C:\ArcpyBook\Ch9\DeleteWildfires.py
文件。
3.導(dǎo)入arcpy
模塊。
import arcpy
4.設(shè)置工作空間路徑:
arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"
5.添加try
語句塊:
try:
6.在with
語句中創(chuàng)建一個更新游標(biāo)(UpdateCursor
)的實例:
with arcpy.da.UpdateCursor("FireIncidents",("CONFID_RATIING"),'[CONFID_RATING]=\'POOR\'') as cursor:
7.創(chuàng)建一個計數(shù)器變量用于打印處理進程。確保語句的縮進以位于with
語句塊中:
cntr = 1
8.調(diào)用deleteRow()
方法刪除返回的行。循環(huán)遍歷返回的行,每次刪除一行:
for row in cursor:
cursor.deleteRow()
print "Record number " + str(cntr) + " deleted"
cntr = cntr + 1
9.添加except
語句塊,發(fā)生錯誤時打印錯誤消息:
except Exception as e:
print e.message
10.完整代碼如下:
import arcpy
arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"
try:
with arcpy.da.UpdateCursor("FireIncidents",("CONFID_RATING"),'[CONFID_RATING]=\'POOR\'') as cursor:
cntr = 1
for row in cursor:
cursor.deleteRow()
print "Record number " + str(cntr) + " deleted"
cntr = cntr + 1
except Exception as e:
print e.message
11.保存并運行腳本。隨著腳本的運行,你會看到下面的消息寫入窗口屏幕中。37條記錄從FireIncidents
要素類中刪除:
Record number 1 deleted
Record number 2 deleted
......................
Record number 33 deleted
Record number 34 deleted
Record number 35 deleted
Record number 36 deleted
Record number 37 deleted
How it works...
要素類和表中的行可以調(diào)用更新游標(biāo)(UpdateCursor
)中的deleteRow()
方法來刪除。在本案例中,我們在更新游標(biāo)(UpdateCursor
)構(gòu)造函數(shù)中使用了where
條件語句來限制僅返回CONFID_RATING
字段值為POOR
的記錄。我們之后循環(huán)遍歷游標(biāo)中返回的記錄并調(diào)用deleteRow()
方法來刪除行。
編輯會話中插入行并更新行
在本章中一直提及編輯會話外對表或要素類所執(zhí)行的插入,更新和刪除操作都是永久性且不可恢復(fù)的。編輯會話則讓你擁有了更大的靈活性,可以回滾不想要的更改操作。
Getting ready
目前為止,我們已經(jīng)使用了插入游標(biāo)和更新游標(biāo)向表和要素類中添加數(shù)據(jù),編輯數(shù)據(jù)和刪除數(shù)據(jù)。只是腳本執(zhí)行完成后,這些更改都是永久性且不可恢復(fù)的。數(shù)據(jù)訪問模塊中新的Editor
類支持創(chuàng)建編輯會話和編輯操作。編輯會話中,要素類和表的更改在調(diào)用特定方法來保存應(yīng)用修改之前的臨時數(shù)據(jù)。這一點與ArcGIS桌面軟件中的編輯工具的功能相同。
編輯會話是通過調(diào)用初始化會話的Editor.startEditing()
方法開始。在編輯會話中,你通過調(diào)用Editor.startOperation()
方法開始執(zhí)行編輯操作。之后你可以執(zhí)行各種操作來編輯你的數(shù)據(jù)。這些編輯結(jié)果可以執(zhí)行恢復(fù),重做和中止操作來回滾,向前滾動和取消編輯操作。操作完成后,你可以調(diào)用Editor.stopOperation()
方法,緊接著調(diào)用Editor.stopEditing()
方法。編輯回話的處理過程如下圖所示:
你可以退出會話而不保存所做的修改。在這種情況下,這些修改不會保存。編輯會話允許在會話內(nèi)執(zhí)行操作并可以將修改永久保存到數(shù)據(jù)庫中或是回滾。此外Editor
類還支持撤銷和重做操作。
下面的代碼示例展示了完整的編輯會話過程,包括創(chuàng)建Editor
對象,開始編輯會話和編輯操作,編輯數(shù)據(jù)操作(這里是一個插入操作),停止操作以及最后保存修改結(jié)果來停止編輯會話:
edit = arcpy.da.Editor('Database Connections/Portland.sde')
edit.startEditing()
edit.startOperation()
with.arcpy.da.InsertCursor("Portland.jpg.schools",("SHAPE@XY","Name")) as cursor:
cursor.insertRow((764271.100,686465.725),'New School')
edit.stopOperation()
edit.stopEditing(True)
Editor
類可用于個人地理數(shù)據(jù)庫,文件地理數(shù)據(jù)庫以及ArcSDE地理數(shù)據(jù)庫。此外,編輯會話還可以在版本化的數(shù)據(jù)庫中開啟和關(guān)閉。你只能一次編輯一個工作空間,該工作空間通過將工作空間的引用地址傳遞給Editor
構(gòu)造函數(shù)來指定。Editor
對象創(chuàng)建后就可以調(diào)用所有的方法來執(zhí)行開始操作,停止操作和取消操作,以及撤銷和重做操作。
How to do it...
按照以下步驟在編輯會話中使用更新游標(biāo)(UpdateCursor
):
1.打開IDLE。
2.打開C:\ArcpyBook\Ch9\UpdateWildfires.py
腳本并另存為
C:\ArcpyBook\Ch9\EidtSessionUpdateWildfires.py
文件。
3.我們要對腳本做些修改來更新CONFID_RATING
字段值。
4.刪除下面幾行代碼:
arcpy.AddField_management("FireIncidents","CONFID_RATING","TEXT",10)
print "CONFID_RATING field added to FireIncidents"
5.創(chuàng)建一個Editor
類的實例并開始編輯會話。下面的代碼放到try
語句塊中:
edit = arcpy.da.Editor('C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb')
edit.startEditing(True)
6.如下所示修改if語句:
if row[0] > 40 and row[0] <= 60:
row[1] = 'GOOD'
elif row[0] > 60 and row[0] <= 85:
row[1] = 'BETTER'
else:
row[1] = 'BEST'
7.結(jié)束編輯會話并保存編輯內(nèi)容。下面語句置于計數(shù)器遞增語句下面:
edit.stopEditing(True)
8.完整代碼如下:
import arcpy
arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"
try:
edit = arcpy.da.Editor('C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb')
edit.startEditing(True)
edit.startOperation()
with arcpy.da.UpdateCursor("FireIncidents",("CONFIDENCEVALUE","CONFID_RATING")) as cursor:
cntr = 1
for row in cursor:
if row[0] > 40 and row[0] <= 60:
row[1] = 'GOOD'
elif row[0] > 60 and row[0] <=85:
row[1] = 'BETTER'
else:
row[1] = 'BEST'
cursor.updateRow(row)
print "Record number " + str(cntr) + " updated"
cntr = cntr + 1
edit.stopOperation()
edit.stopEditing(True)
except Exception as e:
print e.message
9.保存并運行腳本。
How it works...
編輯操作應(yīng)在編輯會話中進行,其中編輯會話調(diào)用Editor.startEditing()
方法來初始化。startEditing()
方法接受兩個可選參數(shù)分別為with_undo
以及multiuser_mode
。其中with_undo
參數(shù)接受一個布爾值true/false
,默認(rèn)值為true
。當(dāng)該參數(shù)設(shè)置為true
時,則創(chuàng)建了撤銷和重做堆棧。multiuser_mode
默認(rèn)為true
,當(dāng)該參數(shù)設(shè)置為false
時,你就完全控制了對正在編輯的未版本化或版本化數(shù)據(jù)集。如果數(shù)據(jù)集是未版本化的數(shù)據(jù)集,那么你調(diào)用stopEditing(False)
則不會提交編輯內(nèi)容。而如果設(shè)置為true
,則會提交編輯內(nèi)容。Editor.stopEditing()
方法接受一個布爾值true/false
參數(shù),用來指明編輯內(nèi)容是否保存。默認(rèn)值為true
。
Editor
類支持撤銷和重做操作。我們先看一下撤銷操作。在編輯會話中,可以執(zhí)行許多編輯操作。在這種情況下你需要撤銷之前的操作的話,可以調(diào)用Editor.undoOperation()
方法來移除撤銷堆棧中最近的編輯操作。如下圖所示:
恢復(fù)操作通過調(diào)用Editor.redoOperation()方法來初始化,會恢復(fù)之前撤銷的一步操作。如下圖所示:
讀取要素類的幾何信息
有些時候你需要訪問要素類中要素的幾何信息。Arcpy提供了讀取不同對象幾何信息的功能。
Getting ready
Arcpy中與要素類有關(guān)的幾何對象包括Polygon
,Polyline
,PointGeomtry
以及MultiPoint
,這些對象都可以通過游標(biāo)來訪問。幾何對象與要素類中shape字段有關(guān)。你可以通過幾何對象來讀取要素類中每一個要素的幾何信息。
線(polyline
)與面(polygon
)要素類由包含了多個部分的要素組成。你可以調(diào)用partCount
屬性來返回每個要素的部分?jǐn)?shù)量然后對每個部分調(diào)用getPart()
來循環(huán)遍歷每個點并提取坐標(biāo)信息。點(point
)要素類由包含了每個點坐標(biāo)信息的要素組成,每個要素對應(yīng)一個PointGeometry
對象。
本案例中,你將使用搜索游標(biāo)(SearchCursor
)對象和Polygon
對象來讀取一個面要素類的幾何信息。
How to do it...
按照以下步驟來學(xué)習(xí)如何讀取要素類中每個要素的幾何信息:
1.打開IDLE,創(chuàng)建一個新的腳本。
2.腳本保存為C:\ArcpyBook\Ch9\ReadGeometry.py
文件。
3.導(dǎo)入arcpy
模塊:
import arcpy
4.將SchoolDistricts
面要素類設(shè)置為輸入要素類:
infc = "C:/ArcpyBook/data/CityOfSanAntonio.gdb/SchoolDistricts"
5.基于輸入要素類創(chuàng)建搜索游標(biāo)(SearchCursor
)對象,并返回ObjectID
和Shape
字段。Shape
字段包含了每個要素的幾何信息。游標(biāo)會在for
循環(huán)語句中創(chuàng)建,我們將循環(huán)迭代要素類中的所有要素:
with arcpy.da.SearchCursor(infc,["OID@","SHAPE@"]) as cursor:
for row in cursor:
print "Feature {0}:".format(row[0])
partnum = 0
6.使用for
循環(huán)語句迭代要素的每個部分:
for part in row[1]:
print "Part {0}".format(partnum)
7.使用for
循環(huán)語句循環(huán)遍歷每個部分的節(jié)點并打印X,Y坐標(biāo):
for pnt in part:
if pnt:
print "{0},{1}".format(pnt.X,pnt.Y)
else:
print "Interior Ring"
partnum += 1
8.保存并運行腳本。腳本將每個要素,要素的每個部分以及每個部分的節(jié)點坐標(biāo)信息如下:
Feature 1:
Part 0:
-98.492224986, 29.380866971
-98.489300049, 29.379610054
-98.486967023, 29.378995028
-98.48503096, 29.376808947
-98.481447988, 29.375624018
-98.478799041, 29.374304981
.....................
-98.4472064,29.467672906
-98.44719583,29.46827383
-98.447195407,29.468297826
**How it works...
**
我們一開始先創(chuàng)建一個搜索游標(biāo)對象來保存要素類內(nèi)容。之后使用for
語句循環(huán)遍歷游標(biāo)內(nèi)的每一行。對于每一行數(shù)據(jù),我們再次循環(huán)遍歷所有的幾何部分。對于每個部分,我們返回每個部分相關(guān)的點并打印每個點的x,y坐標(biāo)信息。