ArcGIS Python編程案例(9)-ArcPy數(shù)據(jù)訪問模塊

第八章 數(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ù)的字段。本案例中,我們僅指定返回FacilityName字段。搜索游標(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列表對象。之后我們將提取的值分別賦值給變量latitudelongitude以及confid。之后我們按照插入游標(biāo)(InsertCursor)創(chuàng)建時定義的字段順序?qū)⑦@些值放入一個叫做rowValue的列表變量中。即經(jīng)緯度值對放在前面,之后是可信度值。最后,我們對變量cur調(diào)用insertRow()方法并將新的rowValue變量傳遞給該方法。我們打印一條信息來指明腳本執(zhí)行的進程,同時創(chuàng)建exceptfinally語句來處理錯誤并關(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要素類中的每一個要素,我們會添加一個對可信度值描述性更強的字段并賦值poorfairgoodexcellent。更新字段值之前,腳本會先向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)的幾何對象包括PolygonPolylinePointGeomtry以及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)對象,并返回ObjectIDShape字段。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)信息。


第八章 數(shù)據(jù)查詢和選擇 ||| 第十章 獲取GIS數(shù)據(jù)列表和描述信息

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容