第一步當(dāng)然是打開、修改、保存文件咯,開篇就先講這個。 本篇文章不會深入到文件數(shù)據(jù)內(nèi)部的一個要素、一個點(diǎn)、一個像素元的操作,而是各種文件層面的操作。 使用 Python 調(diào)用 arcpy 添加、修改、保存文件數(shù)據(jù)在不同的應(yīng)用場景下有不同的方式;筆者根據(jù)使用 ArcPy 存取數(shù)據(jù)時是獨(dú)立的,還是需要對 mxd 文件進(jìn)行操作做了分類,有了下面這個樹狀圖,該篇文章也是按照這個分節(jié)的,正好3大節(jié),讀者把這個思路理清就沒問題了,很簡單! 獨(dú)立處理數(shù)據(jù)獨(dú)立的數(shù)據(jù)處理就比較純粹了,完全不涉及到 mxd 文件。 1.讀取 SHP 文件Chapter2/code1.py 文件的代碼如下: # -*- coding:utf-8 -*-import arcpy import os cws = os.getcwd() # 設(shè)置工作空間 arcpy.env.workspace = cws # 可以覆蓋同名文件 arcpy.env.overwriteOutput = True arcpy.CopyFeatures_management("../SHP/Boroughs.shp", "out.shp") CopyFeatures_management 函數(shù):將輸入要素類或圖層復(fù)制到新要素類。該方法常用于保存矢量文件。上面的示例代碼就是將 Boroughs.shp 另存為 out.shp 文件。 可以看到,讀取矢量數(shù)據(jù)非常簡單,直接輸入矢量文件的地址即可。 這里只是一個簡單的演示,僅僅是讀取 shp 文件然后再導(dǎo)出,在實(shí)際生產(chǎn)中,讀取數(shù)據(jù)后通常需要進(jìn)行一定的處理操作,然后才是導(dǎo)出,但是現(xiàn)在僅做展示,所以簡化了流程。
2.讀取數(shù)據(jù)庫文件GDB 數(shù)據(jù)庫是 Esri 官方出品的地理空間數(shù)據(jù)庫。如果直接在 Windows 資源管理器中打開該數(shù)據(jù)庫的話是無法看到具體內(nèi)容的,只能看到類似這樣的文件: 那么如何讀取 gdb 數(shù)據(jù)庫中的文件呢? 實(shí)際上很簡單,在你知道數(shù)據(jù)庫中的文件名稱的前提下,同樣也是可以通過輸入地址獲得文件。 Chapter2/code2.py 文件的代碼如下: # -*- coding:utf-8 -*-import arcpy import os cws = os.getcwd() # 設(shè)置工作空間 arcpy.env.workspace = cws # 可以覆蓋同名文件 arcpy.env.overwriteOutput = True # 導(dǎo)出數(shù)據(jù)庫要素類 ?注釋1? arcpy.CopyFeatures_management("../NYC.gdb/Boroughs", "out2.shp") # 將shp文件導(dǎo)入數(shù)據(jù)庫 ?注釋2? arcpy.CopyFeatures_management("../SHP/Boroughs.shp", "../NYC.gdb/Boroughs2") 可以看到在 ?注釋1? 處,直接輸入數(shù)據(jù)庫的名稱 NYC.gdb,然后斜杠,然后要素類的名稱。這樣就可以讀取數(shù)據(jù)庫中的文件。 同時也支持 shp 文件保存到 gdb 數(shù)據(jù)庫中,可以看到 ?注釋2? 的代碼將 SHP 文件夾中的 Boroughs.shp 文件保存到數(shù)據(jù)庫 NYC.gdb 中。
3.使用 Layer 類使用 arcpy.mapping 中的 Layer 類不僅可以讀取 shp 格式的文件,還可以讀取 .lyr 圖層文件、gdb 數(shù)據(jù)庫中的文件,甚至還可以讀取 .dwg 為后綴的 CAD 工程文件。 Chapter2/code3.py,使用 Layer 類的示例。 # -*- coding:utf-8 -*-import arcpy import os cws = os.getcwd() # 設(shè)置工作空間 arcpy.env.workspace = cws # 可以覆蓋同名文件 arcpy.env.overwriteOutput = True # 使用Layer類 shp_file = arcpy.mapping.Layer("../SHP/Boroughs.shp") arcpy.CopyFeatures_management(shp_file, "out3.shp") # ?注釋1? shp_file2 = arcpy.mapping.Layer("../NYC.gdb/Boroughs") arcpy.mapping.Layer 類中直接輸入 shp 文件的地址即可,如果想要讀取 .lyr 后綴的圖層文件的話也是輸入地址即可。arcpy.mapping.Layer 類可以將單純的地址字符串轉(zhuǎn)換成真正的圖層對象。 在該示例代碼中,shp_file 獲取了arcpy.mapping.Layer 類的返回對象,變量 shp_file 就是 Boroughs.shp 文件的數(shù)據(jù)圖層對象。 ?注釋1?: 使用 Layer 類直接獲得 gdb 數(shù)據(jù)庫中的要素類也是可以的。 使用 Layer 類獲取 cad 文件中的矢量文件對象,見代碼 Chapter2/code4.py import arcpyimport os class CAD2Shp(object): def __init__(self, cad): self.cad = cad self.convert() def convert(self): pt = arcpy.mapping.Layer(self.cad+"\Point") pl = arcpy.mapping.Layer(self.cad+"\Polyline") pg = arcpy.mapping.Layer(self.cad+"\Polygon") arcpy.CopyFeatures_management(pt, "pt.shp") arcpy.CopyFeatures_management(pl, "er") arcpy.CopyFeatures_management(pg, "pg") if __name__ == '__main__': arcpy.env.workspace = os.getcwd() arcpy.env.overwriteOutput = True CAD2Shp(u"設(shè)計圖.dwg") code4.py 示例代碼把文件 設(shè)計圖.dwg 中的線要素、點(diǎn)要素、面要素導(dǎo)出為 shp 格式。設(shè)計圖.dwg 這個文件由于某些原因我沒有放到教程文件中,請注意一下,如果想要測試一下的話可以自己準(zhǔn)備一個 dwg 文件。
4.讀取柵格對象相關(guān)代碼見 Chapter2/code7.py,注意是文件 code7.py 哦! # -*- coding:utf-8 -*-import arcpy import os cws = os.getcwd() # 設(shè)置工作空間 arcpy.env.workspace = cws # 可以覆蓋同名文件 arcpy.env.overwriteOutput = True raster_p = "../Raster/N31E107.tif" # ?注釋1? new_raster = arcpy.sa.Slope(raster_p) # ?注釋2? new_raster.save("../NYC.gdb/raster") new_raster.save("raster.tif") # ?注釋3? raster_obj = arcpy.Raster(raster_p) arcpy.sa.Slope(raster_obj).save("raster2.tif") raster_p 是 dem 柵格文件的地址。 ?注釋1?: arcpy.sa.Slope() 方法是可根據(jù) dem 柵格數(shù)據(jù)判斷柵格表面的各像元中的坡度,是一種使用非常廣泛的空間分析方法。 從這里可以看到,該方法中只傳入了 dem 柵格地址,沒有傳入輸出地址,這也是柵格數(shù)據(jù)與矢量數(shù)據(jù)在 ArcPy 中處理的一個不同之處。 ?注釋2?: 那么如何輸出成果柵格呢?實(shí)際上該方法的返回值就是輸出的坡度柵格,但仍然存在于系統(tǒng)中,使用 save() 方法可以保存到指定的磁盤位置上。 當(dāng)然不僅可以存放在文件夾中,也可以存放進(jìn) gdb 數(shù)據(jù)庫。 ?注釋3?: 上面的 raster_p 僅僅是表示柵格數(shù)據(jù)文件的地址。盡管直接將其傳入方法 arcpy.sa.Slope() 中沒有問題,也成功輸出了結(jié)果。 但是!該程序方法在內(nèi)部是將其裝換成了柵格對象,然后再進(jìn)行處理的。 盡管很多柵格處理的方法都會在內(nèi)部將柵格文件地址轉(zhuǎn)換成柵格對象,但是有的不會,使用柵格代數(shù)計算的時候也不會,你需要使用 arcpy.Raster() 這個類來將柵格文件的地址字符串轉(zhuǎn)換成柵格對象。 并且我強(qiáng)烈建議,在面對柵格數(shù)據(jù)的時候,都自己手動將其轉(zhuǎn)換成柵格對象。就像 ?注釋3? 一樣! 在 mxd 文件基礎(chǔ)上處理數(shù)據(jù)1.獲得 mxd 文件對象1.1什么叫獲得 mxd 文件?為什么放到前頭講?mxd 文件也叫地圖文檔文件,指以 .mxd 作為文件后綴的 ArcGIS Desktop 地圖文檔文件。 在我們處理數(shù)據(jù)、讀取數(shù)據(jù)過程中,縱然大部分時間都是繞過了 ArcGIS,包括 mxd 文件,但是仍然有可能會遇到處理 mxd 文件的情況,比如使用 Python(ArcPy)讀取、替換、修改、導(dǎo)出 mxd 文件中的數(shù)據(jù)或者直接往 mxd 文件中添加數(shù)據(jù)。 在 Python 語言中 mxd 文件會被轉(zhuǎn)化成一個 mxd 文件對象。 程序會把輸入的 mxd 文件地址字符串轉(zhuǎn)換成地圖文檔對象,我們只有根據(jù)這個地圖文檔對象才能一步步的接近 mxd 文件里面的數(shù)據(jù),進(jìn)而執(zhí)行其他更深的操作。 為了在 mxd 文件上處理數(shù)據(jù),獲得 mxd 文件對象是我們的第一步。 arcpy 的 mapping 模塊中提供 MapDocument(path) 函數(shù),可以幫助我們獲得 mxd 文件對象。 下面的內(nèi)容中會有一些獲取 mxd 對象的操作,同時由于還存在著兩種不同的 mxd 文件對象,所以更要把這個東西放到前面講清楚。 1.2兩種 mxd 文件對象arcpy 不能直接創(chuàng)建 mxd 文件。所以如果需要對 mxd 文件進(jìn)行操作的話,需要指定是當(dāng)前的 mxd 文件還是指定已經(jīng)存在的 mxd 文件。 就是由于當(dāng)前和已經(jīng)存在這兩種情況,兩種識別 mxd 文件對象的方式有所區(qū)別。 什么叫當(dāng)前? 在打開的 ArcMap 界面,從內(nèi)置的 Python 窗口或者自定義的工具箱中運(yùn)行代碼,且運(yùn)行的程序代碼需要讀取、修改位于該 ArcMap 中的圖層文件,亦或者向其中添加圖層文件時,就叫當(dāng)前。 在 ArcMap 主界面中,點(diǎn)擊上方標(biāo)準(zhǔn)工具條上的這個標(biāo)志 可以打開自帶的 Python 窗口。 使用 arcpy.mapping.MapDocument(path) 可以創(chuàng)建地圖文檔對象,用于訪問地圖文檔中的屬性和方法。path 參數(shù)是 mxd 文件的地址,字符串。 在當(dāng)前這種情況下,只能傳入?yún)?shù) "CURRENT",這樣就能返回當(dāng)前地圖文檔對象。 import arcpymxd = arcpy.mapping.MapDocument("CURRENT") 在 Python 窗口中輸入代碼并運(yùn)行,見Chapter2/code5.py # -*- coding:utf-8 -*-import arcpy # mxd文檔對象 mxd = arcpy.mapping.MapDocument("CURRENT") # 數(shù)據(jù)框 df = arcpy.mapping.ListDataFrames(mxd)[0] lyr_path = ur"G:\MoveOn\arcpyTutoraial\SHP\Boroughs.shp" lyr = arcpy.mapping.Layer(lyr_path) arcpy.mapping.AddLayer(df, lyr) # 刷新 arcmap 界面 arcpy.RefreshTOC() arcpy.RefreshActiveView() 你現(xiàn)在只需知道這個程序需要在 Python 窗口運(yùn)行,然后它會將文件 Boroughs.shp 添加到當(dāng)前 ArcMap 中。 試著運(yùn)行一下,將 Chapter2/code5.py 中的代碼復(fù)制粘貼到 Python 窗口,然后按回車運(yùn)行,結(jié)果如下圖,成功將 shp 文件添加到當(dāng)前 ArcMap 界面。
了解擴(kuò)展: 自從 ArcGIS 引入 Python 后,也在程序中內(nèi)嵌了一個 Python 交互窗口。 在Python 窗口中,可以高效、便捷、交互式地使用地理處理工具和 ArcGIS 中的 Python 函數(shù)。 可在該窗口中運(yùn)行的 Python 命令包括單行代碼,也包括帶邏輯的復(fù)雜塊。在 Python 窗口中,還可通過自定義或第三方 Python 模塊和庫來實(shí)現(xiàn)其他功能。 Python 窗口,是具有交互功能的,你可以在同一個窗口多次執(zhí)行 Python 代碼,并且交互窗口能夠保存你之前執(zhí)行代碼產(chǎn)生的結(jié)果以及設(shè)定好的全局變量等參數(shù)。 不同于一般情況在代碼運(yùn)行完后程序自動結(jié)束。在 Python 交互窗口中不會立即結(jié)束程序,它保存結(jié)果和參數(shù),等待下一次輸入代碼片段并執(zhí)行。 并且當(dāng)運(yùn)行 Python 代碼報錯時,Python 交互窗口也不會退出,之前保存的結(jié)果和參數(shù)也不會丟失,可以放心使用。 位于 ArcMap 主界面右邊的是 ArcToolBox 工具箱,也是整個 ArcGIS 最核心的功能,不僅有豐富強(qiáng)大的功能,還有不錯的擴(kuò)展性,開發(fā)者可以將自己寫的 Python 代碼在這里封裝成工具箱。 和 Python 窗口一樣,可以使用 "CURRENT" 字符串來獲得當(dāng)前 mxd文件的對象。 更詳細(xì)內(nèi)容先按下不表,因?yàn)楣ぞ呦湎嚓P(guān)內(nèi)容較多較雜,之后有單獨(dú)篇章詳細(xì)說明。 什么叫已經(jīng)存在? 和上面的當(dāng)前相對應(yīng)的是已經(jīng)存在,已經(jīng)存在使用的更加廣泛一些。 在這里我們不再通過傳入 "CURRENT" 參數(shù)來獲取地圖文檔對象,而是使用具體的 mxd 文件的地址。 import arcpymxd = arcpy.mapping.MapDocument("chapter2MXD.mxd") 在這種情況下基本上就不使用 ArcGIS 自帶的 Python 窗口。直接使用 PyCharm 編寫、調(diào)試、運(yùn)行代碼,關(guān)于如何幾分鐘內(nèi)安裝和配置好 PyCharm 可以查看該系列的第一章。 在 PyCharm 運(yùn)行以下代碼,代碼可見于文件 Chapter2/code6.py。 import arcpyarcpy.env.overwriteOutput = True # mxd文檔對象 mxd = arcpy.mapping.MapDocument("chapter2MXD.mxd") # 數(shù)據(jù)框 ?注釋1? df = arcpy.mapping.ListDataFrames(mxd)[0] # ?注釋2? print "DataFrame Scale:{}".format(df.scale) print "DataFrame Extent:{}".format(df.extent) print "DataFrame Type:{}".format(df.type) # ?注釋3? exist_lyr = arcpy.mapping.ListLayers(mxd)[0] print exist_lyr.name # 添加shp到mxd ?注釋4? lyr_path = ur"../SHP/Boroughs.shp" lyr = arcpy.mapping.Layer(lyr_path) arcpy.mapping.AddLayer(df, lyr) # 添加?xùn)鸥駭?shù)據(jù) ?注釋5? raster_p = "../Raster/N31E107.tif" raster_lyr = arcpy.mapping.Layer(raster_p) arcpy.mapping.AddLayer(df, raster_lyr) # ?注釋6? mxd.saveACopy("output.mxd", version="10.1") 運(yùn)行后,你可以見到一個新創(chuàng)建的 mxd 文件:output.mxd。 運(yùn)行成功,一切都非常良好(具體情況說明緊接下面)。 這些區(qū)別終于講完了,總的來說,當(dāng)前和已經(jīng)完成的區(qū)別就是應(yīng)用 mxd 的狀態(tài)不同,一個是針對當(dāng)前的,一個是針對已經(jīng)保存好了的,在語法上的區(qū)別就是 "CURRENT"。后者的實(shí)際應(yīng)用更多。 2.MXD 數(shù)據(jù)操作(溫馨提示,如果頭暈的話,再去看看最上面的目錄和流程表?。?/span> 講完了區(qū)別,現(xiàn)在講講操作的共同點(diǎn)。 共同點(diǎn)從何而來?因?yàn)樯厦鎯煞N形式都應(yīng)用于 mxd 文件上,這就是共同點(diǎn)。 繼續(xù)使用上面最新的示例,Chapter2/code6.py: import arcpyarcpy.env.overwriteOutput = True # mxd文檔對象 mxd = arcpy.mapping.MapDocument("chapter2MXD.mxd") # 數(shù)據(jù)框 ?注釋1? df = arcpy.mapping.ListDataFrames(mxd)[0] # ?注釋2? print "DataFrame Scale:{}".format(df.scale) print "DataFrame Extent:{}".format(df.extent) print "DataFrame Type:{}".format(df.type) # ?注釋3? exist_lyr = arcpy.mapping.ListLayers(mxd)[0] print exist_lyr.name # 添加shp到mxd ?注釋4? lyr_path = ur"../SHP/Boroughs.shp" lyr = arcpy.mapping.Layer(lyr_path) arcpy.mapping.AddLayer(df, lyr) # 添加?xùn)鸥駭?shù)據(jù) ?注釋5? raster_p = "../Raster/N31E107.tif" raster_lyr = arcpy.mapping.Layer(raster_p) arcpy.mapping.AddLayer(df, raster_lyr) # ?注釋6? mxd.saveACopy("output.mxd", version="10.1") 既然獲得了 mxd 對象,下面就是一步一步深入,想剝洋蔥一樣將其中的屬性、信息都讀取出來。 獲得數(shù)據(jù)框 ?注釋1?&?注釋2?: mxd 之下首先就是數(shù)據(jù)框,下面這個叫“圖層”的實(shí)際就是一個數(shù)據(jù)框,一個 mxd 可以創(chuàng)建多個數(shù)據(jù)框;圖層文件必須依附于一個數(shù)據(jù)框,就像下面的 FireCompanies 圖層。 arcpy.mapping.ListDataFrames(),需要傳入 mxd 對象,還支持傳入通配符。返回的是包含數(shù)據(jù)框?qū)ο蟮?/span>列表,注意哦,是列表,就算只有一個數(shù)據(jù)框返回的也是列表,所以我在后面加上了 [0],將數(shù)據(jù)框?qū)ο笕×顺鰜怼?/span> 從 ?注釋2? 可以看到,返回的數(shù)據(jù)框?qū)ο笠舶瞬簧賹傩院头椒ā?/span> 獲取圖層 ?注釋3?: 使用 arcpy.mapping.ListLayers() 可以獲取 mxd 文件中已經(jīng)存在的各種圖層對象,包括矢量和柵格。 和上面獲得數(shù)據(jù)框?qū)ο蟮姆椒ㄒ粯?,返回的也是列表,需注意?/span> 添加圖層 ?注釋4? & ?注釋5?: 添加圖層就不能直接輸入 shp 文件的地址,包括 gdb 數(shù)據(jù)庫中的要素類。 只有要素圖層(FeatureLayer)才能添加到 mxd 文件中,而不是要素類(FeatureClass)。關(guān)于要素圖層和要素類現(xiàn)在不用太在意,只需知道這個概念就好。 所以我們需要使用 arcpy.mapping.Layer 這個方法將要素類變成要素圖層,然后使用 AddLayer 方法即可將該要素圖層添加到指定的數(shù)據(jù)框中(InsertLayer 和 AddLayer 方法類似)。 使用 Layer 類也可以添加?xùn)鸥駭?shù)據(jù), 操作同添加矢量,見 ?注釋5?。 另存 mxd 后,打開該地圖文檔,可以看到內(nèi)容列表中的圖層數(shù)量從一個變成了三個。添加了一個要素圖層、一個柵格圖層。 保存/另存 ?注釋6?: 使用 save() 可以保存修改過的 mxd 文件。 使用 saveACopy() 是另存,可以指定另存文件名稱以及另存的版本。 其他: 替換圖層。使用 arcpy.mapping.UpdateLayer 方法,該方法非常強(qiáng)大,不僅可以直接更換圖層,還可以用于更新圖層的樣式。關(guān)于使用 UpdateLayer 更換樣式可以查看這篇文章; 移除圖層。arcpy.mapping.RemoveLayer() 方法用于移除 mxd 文件中的圖層。 移動圖層。使用 arcpy.mapping.MoveLayer() 方法可以移動圖層(限制太大沒什么用)。
創(chuàng)建數(shù)據(jù)列表我們再看一眼開頭的結(jié)構(gòu)圖。 可以看到最左邊的創(chuàng)建數(shù)據(jù)列表框上寫著“通用”,這是什么意思呢,表示當(dāng)前講的這一節(jié)與先前是否獨(dú)立、是否涉及 mxd 文件都沒有必要的聯(lián)系,是大家都可以使用的方法,也比較簡單。 創(chuàng)建數(shù)據(jù)列表主要涉及 ArcPy 中這幾個函數(shù):
wild_card 表示通配符,這些函數(shù)可以直接搜尋工作空間中有沒有相應(yīng)類型以及與通配符相匹配的文件,然后以列表的形式返回。 使用這些方法可以不再使用文件后綴去篩選矢量文件了。 其中使用最多就是 ListFeatureClasses 和 ListRasters 以下示例見文件 Chapter2/code8.py # -*- coding:utf-8 -*-import arcpy # ?注釋1? arcpy.env.workspace = "../SHP" fcs = arcpy.ListFeatureClasses() for fc in fcs: print fc # ?注釋2? arcpy.env.workspace = "../NYC.gdb" fcs = arcpy.ListFeatureClasses("*Water*") for fc in fcs: print fc ?注釋1?: 以 ../SHP 文件夾作為工作空間。然后返回矢量文件名稱列表。 ?注釋2?: 以 ../NYC.gdb 數(shù)據(jù)庫作為工作空間,使用通配符 *Water* 去匹配文件名稱帶有 Water 的文件,不管 Water 這個單詞在開頭、中間、還是結(jié)尾。 以上。 結(jié)束語該章節(jié)內(nèi)容比較簡單,但是又存在不同的情況,所以這里把所有情況整理記錄下來。 如果讀者以后有遇到相關(guān)問題,可以再來細(xì)細(xì)的查閱。 使用版本:
源代碼、教學(xué)文檔離線小冊子下載: |
|