近日,接到一個博士師兄的要求,希望我寫一個Python程序,將其2006-2099年各年份的帶經緯度的站點模擬數據.csv文件轉爲點shape文件(.shp)。網上有利用arcpy轉的,也有利用shapely包轉的,但是,作爲開源GIS/RS愛好者,gdal/ogr包作爲開源GIS官方(osgeo)社區維護的包,很多較爲底層的操作都能實現,當然,是最好的選擇。不過,由於操作較爲底層也相對較爲繁瑣一些。當然,我們希望儘可能用一個Python包儘可能做更多的事情,如無必要,儘量減少引入依賴的第三方包,以減少後面程序維護的麻煩。
這裏是使用gdal/ogr和pandas(以及Python自帶的包:os,glob包)實現的將csv文件帶經緯度信息的站點csv文件轉爲點shape文件。(csv文件有個字段:站點id(字符串類型),緯度(浮點型),經度(浮點型),站點預測值(浮點型), 注意各字段的精度就行)
.csv文件所在(輸入)路徑:
源代碼如下:
# 導入相關庫
import os
from osgeo import ogr
import pandas as pd
from osgeo import osr
import glob
# 啓動異常報錯提示
ogr.UseExceptions()
# .shp文件保存路徑
shp_path = r'F:\多種模式平均後降尺度\Site149RCP降尺度數據Shp_2006-2099\rcp85\平均氣溫tas'
# 輸入的csv文件路徑
csv_path = r'F:\多種模式平均後降尺度\Site149RCP降尺度數據CSV_2006-2099\rcp85\平均氣溫tas'
for csv_filename in glob.glob(os.path.join(csv_path,'*.csv')):
# 讀入csv文件信息,設置點幾何的字段屬性
csv_df = pd.read_csv(csv_filename)
# 利用.csv文件創建一個點shp文件
# 獲取驅動
driver = ogr.GetDriverByName('ESRI Shapefile')
# 創建數據源
shp_filename = os.path.basename(csv_filename)[:-4] + '.shp'
# 檢查數據源是否已存在
if os.path.exists(os.path.join(shp_path, shp_filename)):
driver.DeleteDataSource(os.path.join(shp_path, shp_filename))
ds = driver.CreateDataSource(os.path.join(shp_path, shp_filename))
# 圖層名
layer_name = os.path.basename(csv_filename)[:-4]
# 定義座標系對象
sr = osr.SpatialReference()
# 使用WGS84地理座標系
sr.ImportFromEPSG(4326)
# 創建點圖層, 並設置座標系
out_lyr = ds.CreateLayer(layer_name, srs = sr, geom_type=ogr.wkbPoint)
# 創建圖層定義
# 利用csv文件中有四個字段創建4個屬性字段
# station字段
station_fld = ogr.FieldDefn('station', ogr.OFTString)
station_fld.SetWidth(6)
out_lyr.CreateField(station_fld)
# Latitude字段
lat_fld = ogr.FieldDefn('latitude', ogr.OFTReal)
lat_fld.SetWidth(9)
lat_fld.SetPrecision(5)
out_lyr.CreateField(lat_fld)
# Longitude字段
lon_fld = ogr.FieldDefn('longitude', ogr.OFTReal)
lon_fld.SetWidth(9)
lon_fld.SetPrecision(5)
out_lyr.CreateField(lon_fld)
# # pr字段
# pr_fld = ogr.FieldDefn('pr', ogr.OFTReal)
# pr_fld.SetWidth(5)
# pr_fld.SetPrecision(2)
# out_lyr.CreateField(pr_fld)
# tas字段
tas_fld = ogr.FieldDefn('tas', ogr.OFTReal)
tas_fld.SetWidth(6)
tas_fld.SetPrecision(2)
out_lyr.CreateField(tas_fld)
# 從layer中讀取相應的feature類型,並創建feature
featureDefn = out_lyr.GetLayerDefn()
feature = ogr.Feature(featureDefn)
# 設定幾何形狀
point = ogr.Geometry(ogr.wkbPoint)
# 讀入csv文件信息,設置點幾何的字段屬性
for i in range(len(csv_df)):
# 設置屬性值部分
# 站點Id
feature.SetField('station', str(csv_df.iloc[i, 0]))
# 緯度
feature.SetField('latitude', float(csv_df.iloc[i, 1]))
# 經度
feature.SetField('longitude', float(csv_df.iloc[i, 2]))
# # pr值
# feature.SetField('pr', float(csv_df.iloc[i, 3]))
# tas值
feature.SetField('tas', float(csv_df.iloc[i, 3]))
# 設置幾何信息部分
# 利用經緯度創建點, X爲經度, Y爲緯度
point.AddPoint(float(csv_df.iloc[i, 2]), float(csv_df.iloc[i, 1]))
feature.SetGeometry(point)
# 將feature寫入layer
out_lyr.CreateFeature(feature)
# 從內存中清除 ds,將數據寫入磁盤中
ds.Destroy()
程序運行後效果:
.shp文件輸出路徑:
QGIS打開.shp文件檢查效果:
打開屬性表和.csv文件對比:
正確無誤,perfect!
從寫代碼到測試代碼再到運行代碼,花了近3小時,不過,好在解決了,記錄一下,以便後面可以參考一下,最近記憶力不太行,寫代碼都要翻下書本、手冊了!