本文介紹基於Python中ArcPy
模組,實現Excel資料讀取並生成向量圖層,同時進行IDW插值與批次掩膜的方法。
1 任務需求
首先,我們來明確一下本文所需實現的需求。
現有一個記錄有北京市部分PM2.5濃度監測站點在2019年05月18日00時至23時(其中不含19時)等23個逐小時PM2.5濃度資料的Excel表格檔案,我們需要將其中的資料依次讀入一個包含北京市各PM2.5濃度監測站點的向量點要素圖層中;隨後,基於這些站點匯入的23
個逐小時PM2.5濃度資料,逐小時對北京市PM2.5濃度加以反距離加權(IDW)方法的插值,即共繪製23
幅插值圖;最後,基於已有的北京市邊界向量資料,分別對這23
幅插值圖加以掩膜。
在這裡,包含北京市各PM2.5濃度監測站點的向量點要素圖層是基於Python基於Excel生成向量圖層及屬性表資訊:ArcPy得到的,如下圖所示。
其中,該向量圖層還包括屬性表,屬性表內容包括每一個站點的編號、地理位置與中文名稱,如下圖所示。
而記錄有北京市部分PM2.5濃度監測站點在2019年05月18日00時至23時(其中不含19時)等23個逐小時PM2.5濃度資料的Excel表格檔案則如下所示,其中包括各站點在23個整點時所監測到的PM2.5濃度。
2 程式碼實現
瞭解了需求後,我們就基於Python中的ArcPy
模組,進行詳細程式碼的撰寫與介紹。
這裡需要說明的是:在編寫程式碼的時候,為了方便執行,所以希望程式碼後期可以在ArcMap中直接透過工具箱執行,即用到Python程式指令碼新建工具箱與自定義工具的方法;因此,程式碼中對於一些需要初始定義的變數,都用到了arcpy.GetParameterAsText()
函式。大家如果只是希望在IDLE中執行程式碼,那麼直接對這些變數進行具體賦值即可。關於Python程式指令碼新建工具箱與自定義工具,大家可以檢視ArcMap將Python寫的程式碼轉為工具箱與自定義工具詳細瞭解。
上面提到需要初始定義的變數一共有十個,其中arcpy.env.workspace
參數列示當前工作空間,csv_path
參數列示儲存有北京市2019年05月18日00時至23時(其中不含19時)逐小時PM2.5濃度資料的.csv
檔案,shape_file_path
參數列示站點資訊向量資料檔案,boundary_file_path
參數列示投影后北京市邊界向量資料檔案,spatial_resolution
參數列示IDW插值結果柵格圖的像元大小,power
參數列示IDW插值時所用距離的冪指數,look_point
參數列示IDW插值時所用最鄰近輸入取樣點數量的整數值,max_distance
參數列示IDW插值時對最鄰近輸入取樣點的限制距離,單位依據地圖座標系確定;idw_result_dir
參數列示IDW插值結果圖層儲存路徑,mask_result_dir
參數列示IDW插值結果圖層經掩膜後儲存路徑。
程式碼的整體思路為:首先利用pd.read_csv
函式讀取記錄有北京市部分PM2.5濃度監測站點在2019年05月18日00時至23時(其中不含19時)等23個逐小時PM2.5濃度資料的Excel表格檔案資料,隨後在北京市各PM2.5濃度監測站點的向量點要素圖層的屬性表中新建23
個列,每一個列表示該監測站點在某一時刻的濃度資料(共有23
個時刻,因此共有23
個列);其次,由於向量要素圖層中的部分站點在Excel檔案中並沒有資料,因此需要將這些站點從向量要素圖層中刪除;最後,分別利用Idw
函式與ExtractByMask
函式進行IDW插值與掩膜。
具體程式碼如下。
# -*- coding: utf-8 -*-
# @author: ChuTianjia
import copy
import arcpy
import pandas as pd
from arcpy.sa import *
arcpy.env.workspace=arcpy.GetParameterAsText(0)
csv_path=arcpy.GetParameterAsText(1)
shape_file_path=arcpy.GetParameterAsText(2)
idw_result_dir=arcpy.GetParameterAsText(8)
boundary_file_path=arcpy.GetParameterAsText(3)
mask_result_dir=arcpy.GetParameterAsText(9)
spatial_resolution=arcpy.GetParameterAsText(4)
power=arcpy.GetParameterAsText(5)
look_point=arcpy.GetParameterAsText(6)
max_distance=arcpy.GetParameterAsText(7)
csv_data=pd.read_csv(csv_path,header=0,encoding="gbk")
column_name_list=list(csv_data)
hour_column=csv_data["hour"]
pm_25_list=[[0]*len(csv_data) for i in range(csv_data.shape[1]-3)]
for i in range(3,csv_data.shape[1]):
for index,data in csv_data.iterrows():
pm_25_list[i-3][index]=data[i]
field_list=["hour_00","hour_01","hour_02","hour_03","hour_04","hour_05",\
"hour_06","hour_07","hour_08","hour_09","hour_10",\
"hour_11","hour_12","hour_13","hour_14","hour_15",\
"hour_16","hour_17","hour_18","hour_20",\
"hour_21","hour_22","hour_23"]
field_list_use=copy.deepcopy(field_list)
field_list_use.insert(0,"Name")
# Update the columns in the attribute table
for i in range(len(field_list)):
arcpy.AddField_management(shape_file_path,field_list[i],"SHORT")
delete_num=0
delete_name=[]
with arcpy.da.UpdateCursor(shape_file_path,field_list_use) as cursor:
for row in cursor:
for column_name in column_name_list:
if column_name==row[0]:
for i in range(len(csv_data[column_name])):
row[i+1]=csv_data[column_name][i]
cursor.updateRow(row)
# Find stations that without any data
if row[0] not in column_name_list:
cursor.deleteRow()
delete_num+=1
delete_name.append(row[0])
arcpy.AddWarning("Delete {0} site(s) that do not contain any data, and the site(s) name is(are):".format(delete_num))
for i in delete_name:
arcpy.AddMessage(i)
arcpy.AddMessage("\n")
# Perform IDW interpolation
arcpy.env.extent=boundary_file_path
for i in range(len(field_list)):
idw_result=Idw(shape_file_path,field_list[i],spatial_resolution,power,RadiusVariable(look_point,max_distance))
idw_result_path=idw_result_dir+"\\"+"BJ_"+field_list[i]+".tif"
idw_result.save(idw_result_path)
arcpy.AddMessage("{0} has completed IDW interpolation.".format(field_list[i]))
# Perform mask
tif_file_list=arcpy.ListRasters("BJ_hour_*","TIF")
for raster in tif_file_list:
mask_result=ExtractByMask(raster,boundary_file_path)
mask_result_path=mask_result_dir+"\\"+raster.strip(".tif")+"_Mask.tif"
mask_result.save(mask_result_path)
arcpy.AddMessage("{0} has been masked.".format(raster.strip(".tif")))
3 執行結果
執行上述程式碼,如果是在ArcMap中直接透過工具箱執行,則可以看到程式碼執行過程中出現的提示。
例如,下圖所示提示可以知道有哪幾個站點是沒有資料、從而被剔除的。
下圖則可以顯示出目前程式碼的執行情況。
同時,在我們設定的結果資料夾中可以看到,23
小時的插值圖與掩膜圖都將自動生成並儲存在指定資料夾。
再來看看具體的圖片長什麼樣子。
首先檢視IDW插值結果圖;我們以當日10時的插值結果圖為例進行檢視。可以看到其已對北京市邊界向量資料所包含的矩形範圍完成了插值。
接下來,檢視IDW插值結果圖經過掩膜後的影像;我們同樣以當日10時的插值、掩膜結果圖為例進行檢視。可以看到,經過掩膜操作後的影像已經完全符合北京市邊界向量資料的範圍。
至此,大功告成。