【气象常用】EOF分解

效果图:

主要步骤:

1. 数据准备:我用的1950-2023年夏季的温度数据(更多数据下载方法可看:【数据下载】ERA5地表月平均数据下载_era5月平均数据哪里下-CSDN博客

【数据下载】CMIP6数据下载-CSDN博客

【数据下载】ERA5 各高度层月平均数据下载-CSDN博客

2. 数据处理:计算了每年的夏季平均温度,及温度距平,并进行了数据淹没

3. 图像绘制:绘制了eof的前四个模态

详细代码:着急的直接拖到最后有完整代码

步骤一:导入库包及图片存储路径并设置中文字体为宋体,西文为新罗马(没有的库包要先下好奥)

###############################################################################
# 导入库及文件
from netCDF4 import Dataset
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import netCDF4 as nc
from cnmaps import get_adm_maps, draw_maps
from matplotlib import rcParams
import cartopy.feature as cfeature
from eofs.standard import Eof
from cartopy.mpl import ticker
config = {
            "font.family": 'serif',
            "font.size": 12,
            "mathtext.fontset": 'stix',
            "font.serif": ['SimSun'],
         }
rcParams.update(config)
rcParams['axes.unicode_minus']=False
###############################################################################

步骤二:读入数据

###############################################################################
# 读入文件及数据
datapath = r'H:/00.csdn/01data/'
figpath = r'H:/00.csdn/02fig/'
shppath = r'H:/00.csdn/04shp/cn_shp/Province_9/Province_9.shp'

data_tem = Dataset(datapath + 't2m_cn_jja_1950-2023.nc', mode='r')
# print(data_tem)
lons = data_tem.variables['longitude'][:]
lats = data_tem.variables['latitude'][:]
lon, lat = np.meshgrid(lons, lats)
time = data_tem.variables['time']
time_new = nc.num2date(time[:], time.units)
# print(time_new)
tem = data_tem.variables['t2m'][:]

data_tem.close()

步骤三:计算夏季温度平均及温度距平,并对数据进行掩膜

##############################################################################
# 计算每年的夏季平均
t_mean = np.empty((74, 601, 901))
for i in range(0, 74, 1):
    t_mean[i, :, :] = np.mean(tem[i*3 : (i+1)*3, : :], 0)
    
# 计算温度距平
dt = t_mean - np.mean(t_mean, 0)

# 掩膜数据
SC = get_adm_maps(province='四川省', only_polygon=True, record='first')
maskout_t = SC.maskout(lon, lat, dt)

步骤四:创建eof分解器(只需在Eof(maskout_t)中将maskout_t换成自己的数据就好啦)

###############################################################################
# 创建EOF分解器
solver = Eof(maskout_t)
eof = solver.eofsAsCorrelation(neofs=4)
pc = solver.pcs(npcs=4, pcscaling=1)
var = solver.varianceFraction(neigs=4)

步骤五:绘制eof的前四个空间模态

###############################################################################
# 绘制图像
fig=plt.figure(figsize=(15, 15))
proj=ccrs.PlateCarree(central_longitude=180)
lonW,lonE,latS,latN=(97, 109, 25, 35)

# 绘制空间模态
def sp_plot(value, location, title, var):
    fig_ax = fig.add_axes(location, projection=proj)
    fig_ax.set_extent([lonW, lonE, latS, latN], crs=ccrs.PlateCarree())
    fig_ax.set_xticks(list(range(lonW, lonE+1, 3)), crs=ccrs.PlateCarree())
    fig_ax.set_yticks(list(range(latS, latN+1, 3)), crs=ccrs.PlateCarree())
    fig_ax.add_feature(cfeature.OCEAN, edgecolor='black')
    fig_ax.add_feature(cfeature.LAKES, alpha=0.5)
    fig_ax.add_feature(cfeature.COASTLINE, lw=1)
    fig_ax.xaxis.set_major_formatter(ticker.LongitudeFormatter())
    fig_ax.yaxis.set_major_formatter(ticker.LatitudeFormatter())

    draw_maps(get_adm_maps(province='四川省', level='省'), color='k', linewidth=1)
    fig_ax.set_title(title, loc='left', fontsize =15)
    fig_ax.set_title('%.2f%%' % (var*100), loc='right', fontsize =15)
    c = fig_ax.contourf(lons, lats, value, levels=np.arange(-1, 1, 0.05), 
                        zorder=0, extend='both', transform=ccrs.PlateCarree(), cmap=plt.cm.RdBu_r)
    return c

f1 = sp_plot( eof[0,:,:], [0.1,0.99,0.47,0.2], '(a) EOF1', var[0])    
f2 = sp_plot( eof[1,:,:], [0.1,0.74,0.47,0.2], '(c) EOF2', var[1])   
f3 = sp_plot( eof[2,:,:], [0.1,0.49,0.47,0.2], '(e) EOF3', var[2])   
f4 = sp_plot( eof[3,:,:], [0.1,0.24,0.47,0.2], '(g) EOF4', var[3])   

cbposition=fig.add_axes([0.19, 0.2, 0.3, 0.015])
fig.colorbar(f4, cax=cbposition, orientation='horizontal', format='%.1f')

步骤六:绘制eof的前四个pc

# 绘制pc
def time_plot(value, location, title):
    fig0 = fig.add_axes(location)
    fig0.set_title(title, loc='left', fontsize = 15)
    fig0.set_ylim(-4, 4)
    fig0.axhline(0, linestyle="--")
    fig0.plot(np.arange(1950, 2024, 1), value, color='blue')
    # return fig0
    
f5 = time_plot(pc[:,0],[0.55, 0.99, 0.47, 0.2], '(b) PC1')
f6 = time_plot(pc[:,1],[0.55, 0.74, 0.47, 0.2], '(d) PC2')
f7 = time_plot(pc[:,2],[0.55, 0.49, 0.47, 0.2], '(f) PC3')
f8 = time_plot(pc[:,3],[0.55, 0.24, 0.47, 0.2], '(h) PC4')


步骤七:保存图像

###########################################################################
# 存图
plt.savefig(figpath+'207 温度 eof分解', dpi=600, bbox_inches = 'tight')
plt.show()

完整代码在这里:

###############################################################################
# 导入库及文件
from netCDF4 import Dataset
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import netCDF4 as nc
from cnmaps import get_adm_maps, draw_maps
from matplotlib import rcParams
import cartopy.feature as cfeature
from eofs.standard import Eof
from cartopy.mpl import ticker
config = {
            "font.family": 'serif',
            "font.size": 12,
            "mathtext.fontset": 'stix',
            "font.serif": ['SimSun'],
         }
rcParams.update(config)
rcParams['axes.unicode_minus']=False
###############################################################################
###############################################################################
# 读入文件及数据
datapath = r'H:/00.csdn/01data/'
figpath = r'H:/00.csdn/02fig/'
shppath = r'H:/00.csdn/04shp/cn_shp/Province_9/Province_9.shp'

data_tem = Dataset(datapath + 't2m_cn_jja_1950-2023.nc', mode='r')
# print(data_tem)
lons = data_tem.variables['longitude'][:]
lats = data_tem.variables['latitude'][:]
lon, lat = np.meshgrid(lons, lats)
time = data_tem.variables['time']
time_new = nc.num2date(time[:], time.units)
# print(time_new)
tem = data_tem.variables['t2m'][:]

data_tem.close()
##############################################################################
# 计算每年的夏季平均
t_mean = np.empty((74, 601, 901))
for i in range(0, 74, 1):
    t_mean[i, :, :] = np.mean(tem[i*3 : (i+1)*3, : :], 0)
    
# 计算温度距平
dt = t_mean - np.mean(t_mean, 0)

# 掩膜数据
SC = get_adm_maps(province='四川省', only_polygon=True, record='first')
maskout_t = SC.maskout(lon, lat, dt)
###############################################################################
# 创建EOF分解器
solver = Eof(maskout_t)
eof = solver.eofsAsCorrelation(neofs=4)
pc = solver.pcs(npcs=4, pcscaling=1)
var = solver.varianceFraction(neigs=4)
###############################################################################
# 绘制图像
fig=plt.figure(figsize=(15, 15))
proj=ccrs.PlateCarree(central_longitude=180)
lonW,lonE,latS,latN=(97, 109, 25, 35)

# 绘制空间模态
def sp_plot(value, location, title, var):
    fig_ax = fig.add_axes(location, projection=proj)
    fig_ax.set_extent([lonW, lonE, latS, latN], crs=ccrs.PlateCarree())
    fig_ax.set_xticks(list(range(lonW, lonE+1, 3)), crs=ccrs.PlateCarree())
    fig_ax.set_yticks(list(range(latS, latN+1, 3)), crs=ccrs.PlateCarree())
    fig_ax.add_feature(cfeature.OCEAN, edgecolor='black')
    fig_ax.add_feature(cfeature.LAKES, alpha=0.5)
    fig_ax.add_feature(cfeature.COASTLINE, lw=1)
    fig_ax.xaxis.set_major_formatter(ticker.LongitudeFormatter())
    fig_ax.yaxis.set_major_formatter(ticker.LatitudeFormatter())

    draw_maps(get_adm_maps(province='四川省', level='省'), color='k', linewidth=1)
    fig_ax.set_title(title, loc='left', fontsize =15)
    fig_ax.set_title('%.2f%%' % (var*100), loc='right', fontsize =15)
    c = fig_ax.contourf(lons, lats, value, levels=np.arange(-1, 1, 0.05), 
                        zorder=0, extend='both', transform=ccrs.PlateCarree(), cmap=plt.cm.RdBu_r)
    return c

f1 = sp_plot( eof[0,:,:], [0.1,0.99,0.47,0.2], '(a) EOF1', var[0])    
f2 = sp_plot( eof[1,:,:], [0.1,0.74,0.47,0.2], '(c) EOF2', var[1])   
f3 = sp_plot( eof[2,:,:], [0.1,0.49,0.47,0.2], '(e) EOF3', var[2])   
f4 = sp_plot( eof[3,:,:], [0.1,0.24,0.47,0.2], '(g) EOF4', var[3])   

cbposition=fig.add_axes([0.19, 0.2, 0.3, 0.015])
fig.colorbar(f4, cax=cbposition, orientation='horizontal', format='%.1f')

# 绘制pc
def time_plot(value, location, title):
    fig0 = fig.add_axes(location)
    fig0.set_title(title, loc='left', fontsize = 15)
    fig0.set_ylim(-4, 4)
    fig0.axhline(0, linestyle="--")
    fig0.plot(np.arange(1950, 2024, 1), value, color='blue')
    # return fig0
    
f5 = time_plot(pc[:,0],[0.55, 0.99, 0.47, 0.2], '(b) PC1')
f6 = time_plot(pc[:,1],[0.55, 0.74, 0.47, 0.2], '(d) PC2')
f7 = time_plot(pc[:,2],[0.55, 0.49, 0.47, 0.2], '(f) PC3')
f8 = time_plot(pc[:,3],[0.55, 0.24, 0.47, 0.2], '(h) PC4')

###########################################################################
# 存图
plt.savefig(figpath+'207 温度 eof分解', dpi=600, bbox_inches = 'tight')
plt.show()
  • 22
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
EOF分解(Empirical Orthogonal Function decomposition)是一种主成分分析方法,用于分解多维数据集中的空间和时间变化模态。在气象和海洋学中,EOF分解常用于分析海表面温度、气压等大气和海洋场的变化模态。 以下是使用Python进行EOF分解的示例代码: ```python import numpy as np from scipy.linalg import svd # 假设有一个二维数据集,shape为 (n, m),其中 n 是时间步数,m 是空间点数 data = np.random.rand(n, m) # 计算数据集的空间平均值 mean = np.mean(data, axis=0) # 将数据集减去空间平均值,得到去平均后的数据集 data_anomaly = data - mean # 计算数据集的协方差矩阵 covariance_matrix = np.cov(data_anomaly.T) # 对协方差矩阵进行奇异值分解 U, s, V = svd(covariance_matrix) # 提取前 k 个模态 k = 3 modes = U[:, :k] # 计算每个时间步的时间系数 time_coefficients = np.dot(data_anomaly, modes) # 合成前 k 个模态 reconstructed_data = np.dot(time_coefficients, modes.T) + mean # 打印结果 print("EOF modes:") print(modes) print("Time coefficients:") print(time_coefficients) print("Reconstructed data:") print(reconstructed_data) ``` 这段代码首先对数据集进行了去平均处理,然后计算了数据集的协方差矩阵,并对其进行了奇异值分解。接着,根据指定的模态数量 k,提取了前 k 个模态,并计算了每个时间步的时间系数。最后,根据时间系数和模态,合成了重构数据集。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值