前言
地學(xué)、水文、氣象領(lǐng)域的自然科學(xué)數(shù)據(jù)通常以netcdf、hdf、二進制等方式存儲,比如溫度、降水、蒸發(fā)數(shù)據(jù)等;學(xué)會這些數(shù)據(jù)格式的讀取和可視化是進行地學(xué)統(tǒng)計分析計算的關(guān)鍵,python提供了解析nc、hdf等數(shù)據(jù)格式的庫,作者整理了如何利用python進行.nc、.hdf、*.dat格式數(shù)據(jù)的讀取并進行柵格轉(zhuǎn)換,歡迎轉(zhuǎn)載和關(guān)注!
arcpy讀取二進制文件---以GSMaP降水?dāng)?shù)據(jù)集為例
溫度、降水、蒸發(fā)等科學(xué)數(shù)據(jù)為了達到壓縮文件大小,易于存儲和維護等目的,通常在下載后往往以二進制.bin、.dat等方式呈現(xiàn)。因此在進行數(shù)據(jù)分析和統(tǒng)計計算時需要讀取二進制文件進行數(shù)據(jù)還原。
注意: 讀取二進制文件要特別要注意到 二進制文件數(shù)據(jù)存儲的端序問題(字節(jié)序),小端序需要進行端序轉(zhuǎn)換!
- 本地文件夾下存在2018年6月份前10天的日尺度降水?dāng)?shù)據(jù)集,下面利用arcoy腳本將該數(shù)據(jù)批量轉(zhuǎn)換為tiff柵格影像,并在arcmap中展示。
代碼展示
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Name : gsmap2TIFF.py
# Author : zengsk in NanJing
# Created: 2019/8/24 23:26
'''
說明:1.該腳本是讀取gsmap小時尺度降水?dāng)?shù)據(jù),輸出為tiff
2.運行環(huán)境需要安裝python2 需要arcpy模塊
3.使用arcgis自帶的python環(huán)境(有arcpy模塊)
4.運行結(jié)果可以直接用arcgis打開
'''
# 導(dǎo)入module
import os
import glob
import numpy as np
import arcpy
import warnings
warnings.simplefilter("ignore") # 忽略警告
# 原始降水?dāng)?shù)據(jù)文件夾,可根據(jù)自己本地情況修改
sPath = r'H:\test\gsmap'
oDir = r"H:\test\res"
for fileName in glob.glob(sPath+'\*.dat'):
print("Processing... {0}".format(fileName))
ds = np.fromfile(fileName, dtype=np.float32)
ds = np.resize(ds,[1200,3600])
ds[ds < 0] = -999.00
ds[np.isnan(ds)] = -999.00 # NODATA_value
# 輸出為TIFF(注意:要用到arcpy模塊)
if not os.path.exists(oDir):
os.makedirs(oDir)
TiffName = oDir + os.sep + os.path.basename(fileName)[0:-4] + '.tif' # 輸出文件名(可根據(jù)實際情況改)
# arcpy.NumPyArrayToRaster()不清楚輸入?yún)?shù)可以查看arcpy的官方文檔
# 矩陣轉(zhuǎn)為柵格
raster = arcpy.NumPyArrayToRaster(ds, arcpy.Point(0, -60.0),
x_cell_size=0.1, y_cell_size=0.1, value_to_nodata=-999.00)
# 添加地理坐標(biāo)系 GCS_WGS_1984
spatialRef = arcpy.SpatialReference(4326)
arcpy.DefineProjection_management(raster, spatialRef)
raster.save(TiffName)
print("\n++++++ Data Processing Successfully Completed ! ++++++")
處理結(jié)果
arcmap中展示
NetCDF(*.nc)文件轉(zhuǎn)GeoTIFF---以GLDAS路面蒸發(fā)數(shù)據(jù)為例
在地學(xué)領(lǐng)域,nc格式的文件可謂隨處可見,netCDF文件可以存儲多維數(shù)字矩陣,同時又封裝了自描述信息(例如經(jīng)緯度、高度層、時間戳、單位等)。nc文件的IO接口也很普及,Python、NCL、Matlab等氣象上常用的軟件都可以對其進行讀寫操作。用Python對nc文件的讀寫操作是使用Python進行氣象數(shù)據(jù)分析最基礎(chǔ)的部分之一。
基于Python處理nc數(shù)據(jù)必要的庫是netCDF4,同時如果需要將nc文件轉(zhuǎn)換為tiff文件,還需要osgeo庫中的gdal子庫和osr子庫。**
下面以GLDAS全球陸地蒸發(fā)數(shù)據(jù)為例,展示如何利用python讀取nc文件并將數(shù)據(jù)轉(zhuǎn)換為geotiff文件。
源碼
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Name : gldas2tiff.py
# Author : zengsk in NanJing
# Created: 2020/5/13 17:02
"""
Details: 讀取GLDAS_NOAH025的蒸發(fā)數(shù)據(jù)(netcdf格式)并轉(zhuǎn)為Tiff柵格影像
"""
import netCDF4 as nc
from osgeo import gdal, osr
import numpy as np
# ('Evap_tavg', <class 'netCDF4._netCDF4.Variable'>
# float32 Evap_tavg(time, lat, lon)
# units: kg m-2 s-1
# standard_name: water_evaporation_flux
# long_name: Evapotranspiration
# cell_methods: time: mean
# scale_factor: 1.0
# add_offset: 0.0
# missing_value: -9999.0
# _FillValue: -9999.0
# vmin: -1.8462154e-06
# vmax: 7.190982e-05
# unlimited dimensions: time
# current shape = (1, 600, 1440)
# filling off
# )
def nc2tiff(nc_url, var='Evap_tavg', save_name='./nc2tiff.tif'):
"""
:param nc_url: netcdf文件的路徑
:param var: 讀取nc文件的變量名稱, 默認(rèn) Evap_tavg
:param save_name: 輸出tiff文件的保存路徑
:return:
"""
print(nc_url)
nc_fp = nc.Dataset(nc_url)
# 查看屬性
print(nc_fp)
# # 查看變量
print(nc_fp.variables)
# 獲取var數(shù)據(jù)集
evap = nc_fp.variables[var][:] # 單位轉(zhuǎn)換 kg m-2 s-1
evap = np.array(evap)
evap = np.squeeze(evap)
# missing value 處理
fillvalue = nc_fp.variables[var].missing_value
evap[evap == fillvalue] = np.nan
evap = evap * 3600 * 24 * 30
array2raster(evap, 0.25, 0.25, [-180, -60], save_name)
# 數(shù)據(jù)矩陣轉(zhuǎn)tiff文件
def array2raster(array, xsize, ysize, rasterOrigin, newTiffName):
"""
array: 計算后的柵格數(shù)據(jù)
xsize: x方向像元大小
ysize: y方向像元大小
rasterOrigin: 原始柵格數(shù)據(jù)Extent
newRasterfn: 輸出tif路徑
"""
cols = array.shape[1] # 矩陣列數(shù)
rows = array.shape[0] # 矩陣行數(shù)
originX = rasterOrigin[0] # 起始像元經(jīng)度
originY = rasterOrigin[1] # 起始像元緯度
driver = gdal.GetDriverByName('GTiff')
outRaster = driver.Create(newTiffName, cols, rows, 1, gdal.GDT_Float32)
# 設(shè)置仿射矩陣參數(shù)(左上角X坐標(biāo); X方向分辨率; 旋轉(zhuǎn)角度,如果圖像北方朝上,該值為0; 左上角Y坐標(biāo); 旋轉(zhuǎn)角度; y方向分辨率)
outRaster.SetGeoTransform((originX, xsize, 0, originY, 0, ysize))
# 獲取數(shù)據(jù)集第一個波段,是從1開始,不是從0開始
outband = outRaster.GetRasterBand(1)
outband.WriteArray(array)
spatialRef = osr.SpatialReference()
# 代碼4326表示W(wǎng)GS84坐標(biāo)
spatialRef.ImportFromEPSG(4326)
outRaster.SetProjection(spatialRef.ExportToWkt())
outband.FlushCache()
outRaster.FlushCache()
# 主函數(shù)
if __name__ == '__main__':
netcdf_url = r'E:\Scripts\Test\GLDAS_NOAH025_M.A200002.021.nc4'
nc2tiff(netcdf_url, "Evap_tavg", save_name='E:\Scripts\Test\evap2tiff.tif')
print("\n++++++ Data Processing Successfully Completed ! ++++++")
結(jié)果在arcmap中顯示
讀取hdf文件(*.hdf)并轉(zhuǎn)為tif文件---以MODIS地面溫度數(shù)據(jù)為例
HDF文件是地學(xué)研究中常用的數(shù)據(jù)格式,衛(wèi)星數(shù)據(jù)的儲存格式通常如此。下面以MODIS 16A3 地表溫度數(shù)據(jù)為例,進行LST數(shù)據(jù)的讀取和TIFF格式轉(zhuǎn)換。
- 利用python讀取hdf文件需要用的pyhdf庫,lst數(shù)據(jù)轉(zhuǎn)換為geotiff文件則采用GDAL庫。
源碼
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Name : modis2tiff.py
# Author : zengsk in NanJing
# Created: 2020/5/17 20:28
"""
Details:
"""
from pyhdf import SD
from osgeo import gdal, osr
import numpy as np
def hdf2tiff(hdf_url, variable, save_name="./hdf2tiff.tiff"):
fp = SD.SD(hdf_url)
for idx, sds in enumerate(fp.datasets().keys()):
print(idx, sds)
# print(fp.select(variable).attributes())
lst = fp.select(variable).get()
lst[lst == -9999.0] = np.nan
lst -= 273.15 # 轉(zhuǎn)換為攝氏度
array2raster(lst, 1.0, -1.0, [-180, 90], save_name)
def array2raster(array, xsize, ysize, rasterOrigin, newTiffName):
"""
array: 計算后的柵格數(shù)據(jù)
xsize: x方向像元大小
ysize: y方向像元大小
rasterOrigin: 原始柵格數(shù)據(jù)Extent
newRasterfn: 輸出tif路徑
"""
cols = array.shape[1] # 矩陣列數(shù)
rows = array.shape[0] # 矩陣行數(shù)
originX = rasterOrigin[0] # 起始像元經(jīng)度
originY = rasterOrigin[1] # 起始像元緯度
driver = gdal.GetDriverByName('GTiff')
outRaster = driver.Create(newTiffName, cols, rows, 1, gdal.GDT_Float32)
# 設(shè)置仿射矩陣參數(shù)(左上角X坐標(biāo); X方向分辨率; 旋轉(zhuǎn)角度,如果圖像北方朝上,該值為0; 左上角Y坐標(biāo); 旋轉(zhuǎn)角度; y方向分辨率)
outRaster.SetGeoTransform((originX, xsize, 0, originY, 0, ysize))
# 獲取數(shù)據(jù)集第一個波段,是從1開始,不是從0開始
outband = outRaster.GetRasterBand(1)
outband.WriteArray(array)
spatialRef = osr.SpatialReference()
# 代碼4326表示W(wǎng)GS84坐標(biāo)
spatialRef.ImportFromEPSG(4326)
outRaster.SetProjection(spatialRef.ExportToWkt())
outband.FlushCache()
if __name__ == '__main__':
hdf_url = r'E:\Scripts\Test\LST\MOD11CM1_v005_day___lst_2000m03.hdf'
hdf2tiff(hdf_url, "day_lst", save_name=r'E:\Scripts\Test\LST_TIFF2.tif')
print("\n++++++ Data Processing Successfully Completed ! ++++++")