目录
1.环境准备
2.设置文件路径
3.读取矢量数据
4.定义年份和季节
5.创建输出文件夹
6.裁剪栅格数据的函数
7.计算和保存年度平均降水数据
8.计算和保存季节平均降水数据
9.结论
10.完整代码
本次分享内容中,我们将介绍如何使用Python计算和裁剪年度和季节的降水栅格数据。本教程主要涉及到以下内容:
- 计算2000-2021年的年度和季节平均降水量;
- 使用研究区域矢量数据裁剪出研究区域的降水栅格数据。
我们将使用 rasterio
和 geopandas
两个库来实现这些操作。
图1|现有需要计算处理和裁剪的降水栅格数据
1.环境准备
首先,确保你的Python环境中已经安装了必要的库。如果没有的话,你可以使用以下命令来安装这些库(在Anaconda进行):
pip install rasterio geopandas numpy
2.设置文件路径
将文件路径设置为你自己的数据文件夹路径和矢量数据路径:
import os
import rasterio
import numpy as np
import geopandas as gpd
from rasterio.mask import mask
input_folder = r"你的降水栅格数据文件夹路径"
output_folder = r"保存结果的文件夹路径"
clipped_output_folder = r"保存裁剪后结果的文件夹路径"
shapefile_path = r"矢量数据文件路径"
3.读取矢量数据
使用 geopandas
读取研究区域的矢量数据:
shapefile = gpd.read_file(shapefile_path)
4.定义年份和季节
设置要处理的年份和季节:
years = list(range(2000, 2021)) # 从2000到2020年
seasons = {
"spring": [3, 4, 5],
"summer": [6, 7, 8],
"autumn": [9, 10, 11],
"winter": [12, 1, 2]
}
5.创建输出文件夹
确保输出文件夹存在:
os.makedirs(output_folder, exist_ok=True)
os.makedirs(clipped_output_folder, exist_ok=True)
6.裁剪栅格数据的函数
定义一个函数来裁剪栅格数据,并设置无效值:
def clip_raster(raster, shapes, nodata_value):
out_image, out_transform = mask(raster, shapes, crop=True, nodata=nodata_value, filled=False)
out_meta = raster.meta.copy()
out_meta.update({
"height": out_image.shape[1],
"width": out_image.shape[2],
"transform": out_transform,
"nodata": nodata_value
})
return out_image, out_meta
7.计算和保存年度平均降水数据
逐年计算并保存年度平均降水数据,然后裁剪结果:
for year in years:
annual_data = []
for month in range(1, 13):
file = f"{input_folder}/pre{year}{str(month).zfill(2)}.tif"
if os.path.exists(file):
with rasterio.open(file) as src:
data = src.read(1).astype(np.float32)
data[data == src.nodata] = np.nan # 替换无效值为NaN
annual_data.append(data)
if annual_data:
annual_mean = np.nanmean(np.array(annual_data), axis=0) # 忽略NaN值
# 保存年度平均降水数据
output_file = f"{output_folder}/annual_mean_{year}.tif"
with rasterio.open(
output_file, 'w',
driver='GTiff',
height=annual_mean.shape[0],
width=annual_mean.shape[1],
count=1,
dtype=annual_mean.dtype,
crs=src.crs,
transform=src.transform,
nodata=np.nan
) as dst:
dst.write(annual_mean, 1)
# 裁剪年度平均降水数据
with rasterio.open(output_file) as src:
out_image, out_meta = clip_raster(src, shapefile.geometry, nodata_value=np.nan)
clipped_output_file = f"{clipped_output_folder}/annual_mean_{year}_clipped.tif"
with rasterio.open(clipped_output_file, 'w', **out_meta) as dst:
dst.write(out_image[0], 1)
8.计算和保存季节平均降水数据
逐年逐季计算并保存季节平均降水数据,然后裁剪结果:
for year in years:
for season, months in seasons.items():
season_data = []
for month in months:
if month == 1 or month == 2: # 处理跨年的冬季月份
season_year = year + 1
else:
season_year = year
file = f"{input_folder}/pre{season_year}{str(month).zfill(2)}.tif"
if os.path.exists(file):
with rasterio.open(file) as src:
data = src.read(1).astype(np.float32)
data[data == src.nodata] = np.nan # 替换无效值为NaN
season_data.append(data)
if season_data:
season_mean = np.nanmean(np.array(season_data), axis=0) # 忽略NaN值
# 保存季节平均降水数据
output_file = f"{output_folder}/season_mean_{season}_{year}.tif"
with rasterio.open(
output_file, 'w',
driver='GTiff',
height=season_mean.shape[0],
width=season_mean.shape[1],
count=1,
dtype=season_mean.dtype,
crs=src.crs,
transform=src.transform,
nodata=np.nan
) as dst:
dst.write(season_mean, 1)
# 裁剪季节平均降水数据
with rasterio.open(output_file) as src:
out_image, out_meta = clip_raster(src, shapefile.geometry, nodata_value=np.nan)
clipped_output_file = f"{clipped_output_folder}/season_mean_{season}_{year}_clipped.tif"
with rasterio.open(clipped_output_file, 'w', **out_meta) as dst:
dst.write(out_image[0], 1)
9.结论
通过上述步骤,我们可以计算年度和季节的平均降水量,并使用矢量数据裁剪结果,使其仅包含研究区域内的有效像素,这样可以更准确地分析研究区域的降水情况。
10.完整代码
import os
import rasterio
import numpy as np
import geopandas as gpd
from rasterio.mask import mask
# 设置文件路径
input_folder = r"你的降水栅格数据文件夹路径"
output_folder = r"保存结果的文件夹路径"
clipped_output_folder = r"保存裁剪后结果的文件夹路径"
shapefile_path = r"矢量数据文件路径"
# 读取矢量数据
shapefile = gpd.read_file(shapefile_path)
# 定义年份和季节
years = list(range(2000, 2021)) # 从2000到2020年
seasons = {
"spring": [3, 4, 5],
"summer": [6, 7, 8],
"autumn": [9, 10, 11],
"winter": [12, 1, 2]
}
# 创建输出文件夹(如果不存在)
os.makedirs(output_folder, exist_ok=True)
os.makedirs(clipped_output_folder, exist_ok=True)
# 裁剪栅格数据的函数
def clip_raster(raster, shapes, nodata_value):
out_image, out_transform = mask(raster, shapes, crop=True, nodata=nodata_value, filled=False)
out_meta = raster.meta.copy()
out_meta.update({
"height": out_image.shape[1],
"width": out_image.shape[2],
"transform": out_transform,
"nodata": nodata_value
})
return out_image, out_meta
# 计算年度平均降水数据
for year in years:
annual_data = []
for month in range(1, 13):
file = f"{input_folder}/pre{year}{str(month).zfill(2)}.tif"
if os.path.exists(file):
with rasterio.open(file) as src:
data = src.read(1).astype(np.float32)
data[data == src.nodata] = np.nan # 替换无效值为NaN
annual_data.append(data)
if annual_data:
annual_mean = np.nanmean(np.array(annual_data), axis=0) # 忽略NaN值
# 保存年度平均降水数据
output_file = f"{output_folder}/annual_mean_{year}.tif"
with rasterio.open(
output_file, 'w',
driver='GTiff',
height=annual_mean.shape[0],
width=annual_mean.shape[1],
count=1,
dtype=annual_mean.dtype,
crs=src.crs,
transform=src.transform,
nodata=np.nan
) as dst:
dst.write(annual_mean, 1)
# 裁剪年度平均降水数据
with rasterio.open(output_file) as src:
out_image, out_meta = clip_raster(src, shapefile.geometry, nodata_value=np.nan)
clipped_output_file = f"{clipped_output_folder}/annual_mean_{year}_clipped.tif"
with rasterio.open(clipped_output_file, 'w', **out_meta) as dst:
dst.write(out_image[0], 1)
# 计算季节平均降水数据
for year in years:
for season, months in seasons.items():
season_data = []
for month in months:
if month == 1 or month == 2: # 处理跨年的冬季月份
season_year = year + 1
else:
season_year = year
file = f"{input_folder}/pre{season_year}{str(month).zfill(2)}.tif"
if os.path.exists(file):
with rasterio.open(file) as src:
data = src.read(1).astype(np.float32)
data[data == src.nodata] = np.nan # 替换无效值为NaN
season_data.append(data)
if season_data:
season_mean = np.nanmean(np.array(season_data), axis=0) # 忽略NaN值
# 保存季节平均降水数据
output_file = f"{output_folder}/season_mean_{season}_{year}.tif"
with rasterio.open(
output_file, 'w',
driver='GTiff',
height=season_mean.shape[0],
width=season_mean.shape[1],
count=1,
dtype=season_mean.dtype,
crs=src.crs,
transform=src.transform,
nodata=np.nan
) as dst:
dst.write(season_mean, 1)
# 裁剪季节平均降水数据
with rasterio.open(output_file) as src:
out_image, out_meta = clip_raster(src, shapefile.geometry, nodata_value=np.nan)
clipped_output_file = f"{clipped_output_folder}/season_mean_{season}_{year}_clipped.tif"
with rasterio.open(clipped_output_file, 'w', **out_meta) as dst:
dst.write(out_image[0], 1)
print("年度和季节平均降水数据计算和裁剪完成!")
图2|计算裁剪之后得到的研究区域降水数据