本文介紹基於Python語言中ArcPy模組,實現ArcMap自動批次出圖,並對地圖要素進行自定義批次設定的方法。
1 任務需求
首先,我們來明確一下本文所需實現的需求。
現有透過Python基於Excel資料加以反距離加權空間插值並掩膜圖層所繪製的北京市在2019年05月18日00時至23時(其中不含19時)等23個逐小時PM2.5濃度插值資料柵格圖層,每小時一個圖層,因此共23個圖層;以當日10時為例,該時刻的柵格圖層如下所示。
我們希望做到的有兩點。首先,我們可以看到前述23個柵格圖層的符號系統都為灰度拉伸的狀態,因此希望按照一個給定的模板圖層檔案m.lyr
,調整這23個柵格圖層的樣式(即拉伸的顏色),並分別以.lyr
格式匯出這23個柵格圖層檔案;且希望匯出圖層檔案的檔名包含具體的時刻。如下圖所示。
第二點希望做到的是,將每一個柵格圖層都設定為彩色後,新增圖名、指北針、比例尺等地圖要素,並匯出為圖片格式。以當日10時、20時為例,我們所希望匯出的圖片如下所示。
且希望匯出圖片的檔名同樣包含具體的時刻。
2 程式碼實現
瞭解了需求後,我們就基於Python中的ArcPy
模組,進行詳細程式碼的撰寫與介紹。
這裡需要說明的是:在編寫程式碼的時候,為了方便執行,所以希望程式碼後期可以在ArcMap中直接透過工具箱執行,即用到Python程式指令碼新建工具箱與自定義工具的方法;因此,程式碼中對於一些需要初始定義的變數,都用到了arcpy.GetParameterAsText()
函式。大家如果只是希望在IDLE中執行程式碼,那麼直接對這些變數進行具體賦值即可。關於Python程式指令碼新建工具箱與自定義工具,大家可以檢視ArcMap將Python寫的程式碼轉為工具箱與自定義工具詳細瞭解。
上面提到需要初始定義的變數一共有七個,其中arcpy.env.workspace
參數列示當前工作空間;mxd_file
參數列示後期批次出圖時,提供地圖要素參考資訊的地圖文件.mxd
檔案;lyr_file
參數列示後期批次出圖時,提供地圖著色參考資訊的模板圖層.lyr
檔案;mask_path
參數列示前述插值柵格圖層所儲存的路徑;new_lyr_path
參數列示插值柵格圖層經過樣式修改,並轉為圖層檔案後的儲存路徑;png_path
參數列示最終出圖結果的儲存路徑;dpi
參數列示最終出圖結果的影像解析度,單位為DPI(Dots per Inch)。
其中,上述第二個引數,即提供地圖要素參考資訊的地圖文件.mxd
檔案需要由使用者自行建立,並在其中配置好圖名、圖例、指北針、比例尺等地圖要素的名稱、文字、位置、樣式等資訊。或許這麼說有點不清楚,大家看下面這幅圖就能比較容易明白了。
沒錯,這個提供地圖要素參考資訊的地圖文件.mxd
檔案其實就是一個在Layout View中設定好各種地圖要素位置、大小、字型、顏色等的地圖文件檔案;它就相當於是一個模板,這個模板裡各種地圖要素長什麼樣子,後期我們批次出圖結果圖的地圖要素就長什麼樣子。
此外,不知道為什麼,在我的ArcMap中似乎偶爾會出現無法有效執行lyr.visible=False
或arcpy.mapping.RemoveLayer(data_frame,new_lyr[0])
等程式碼情況;因此若直接在上述地圖文件檔案中配置圖例,最終出圖結果有時會出現多個圖例堆疊,不能保證出圖結果百分之百完美。基於此,選擇將圖例格式元素(elm.name==”title”
)轉換為由一個圖片格式元素(elm.name==”pic”
)與兩個文字格式元素(elm.name==”text”
)組成的新元素,從而實現最終結果圖中圖例的繪製。
如果大家還是不明白,可以直接下載我的這一.mxd
檔案;下載連結:https://pan.baidu.com/s/18l0l-kjPfdjV1UYcpkKg-w?pwd=fkxx 。
具體程式碼如下。
# -*- coding: utf-8 -*-
# @author: ChuTianjia
import arcpy
arcpy.env.workspace=arcpy.GetParameterAsText(0)
mxd_file=arcpy.GetParameterAsText(1)
lyr_file=arcpy.GetParameterAsText(2)
mask_path=arcpy.GetParameterAsText(3)
new_lyr_path=arcpy.GetParameterAsText(4)
png_path=arcpy.GetParameterAsText(5)
dpi=arcpy.GetParameterAsText(6)
my_mxd=arcpy.mapping.MapDocument(mxd_file)
data_frame=arcpy.mapping.ListDataFrames(my_mxd)[0]
my_lyr=arcpy.mapping.Layer(lyr_file)
layer_list=arcpy.mapping.ListLayers(my_mxd)
my_mxd.activeView="PAGE_LAYOUT"
tif_file_list=arcpy.ListRasters("BJ_hour_*","TIF")
for raster in tif_file_list:
# Import the mask layer into ArcMap
raster_file=mask_path+"\\"+raster
arcpy.MakeRasterLayer_management(raster_file,raster.strip(".tif"))
# Modify the style of the mask layer according to the reference layer
arcpy.ApplySymbologyFromLayer_management(raster.strip(".tif"),lyr_file)
new_lyr_file=new_lyr_path+"\\"+raster.strip(".tif")+".lyr"
# Save and import the mask layer after modifying the style
arcpy.SaveToLayerFile_management(raster.strip(".tif"),new_lyr_file)
arcpy.AddMessage("{0} has been saved.".format(raster.strip(".tif")+".lyr"))
new_lyr=arcpy.mapping.Layer(new_lyr_file)
arcpy.mapping.AddLayer(data_frame,new_lyr,"TOP")
# Modify the image name
for element in arcpy.mapping.ListLayoutElements(my_mxd,"TEXT_ELEMENT"):
if element.name=="title":
element.text="Interpolation Map of PM2.5 Concentration\n at {0}:00 on May 18, 2019, Beijing".format(raster[8:10])
new_lyr.visible=True
# Modify the legend (see the program usage document for details)
max_pixel=arcpy.GetRasterProperties_management(new_lyr,"MAXIMUM").getOutput(0)[0:5]
min_pixel=arcpy.GetRasterProperties_management(new_lyr,"MINIMUM").getOutput(0)[0:5]
for element in arcpy.mapping.ListLayoutElements(my_mxd,"TEXT_ELEMENT"):
if element.name=="MAX":
element.text="{:0>5.2f}".format(float(max_pixel))
if element.name=="MIN":
element.text="{:0>5.2f}".format(float(min_pixel))
# Export to picture format
png_file=png_path+"\\"+raster.strip(".tif")+".png"
arcpy.mapping.ExportToPNG(my_mxd,png_file,resolution=dpi)
arcpy.AddMessage("{0} has been saved.".format(raster.strip(".tif")+".png"))
new_lyr.visible=False
arcpy.mapping.RemoveLayer(data_frame,new_lyr[0])
3 執行結果
執行上述程式碼,具體得到的結果其實在本文開頭也就和大家講了,這裡就不再贅述。
不過還有一點,就是如果大家是在ArcMap中直接透過工具箱執行上述程式碼,則可以看到程式碼執行過程中出現的提示——程式執行過程中,對每一個時刻的PM2.5濃度資料分別完成圖層格式儲存與圖片格式儲存等2個操作後,均會輸出執行結果,方便使用者獲知程式的執行情況。
至此,大功告成。