nc文件曲面坐标转等距离坐标并对NC文件求四季平均值(内涵极地投影坐标系(极射赤道投影))

该博客介绍了如何使用Python的xesmf库将曲面坐标转换为等间距坐标,并展示了利用转换后的数据绘制极射赤道投影地图的过程,适用于处理地理空间数据,特别是海冰厚度数据的分析。文章详细讲解了Linux环境下安装xesmf库的方法,以及代码实现数据插值、按季节平均和作图的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Python库介绍

  1. 本次测试数据为PIOMAS逐月海冰厚度数据,数据链接如下:PIOMAS Variables on Model Grid
  2. 我们以海冰厚度为例,会发现他的坐标系为一个二维矩阵

在这里插入图片描述
接着我们使用python 将longitude输出一下
在这里插入图片描述
当我们看到这种逐行和逐列均不相等的就说明这个一个曲面坐标而非一个等间距坐标,如果我们需要将多组数据混合运算尤其是曲面坐标系与等间距坐标运算,会及其麻烦,那么我今天在这里就向大家介绍一种可以将曲面坐标系化为等间距坐标系的方法。

  1. 核心库函数:xesmf
    xesmf 这个库只在Linux和MAC上有,额好吧,我并不会有什么MAC那种高级的电脑,今天就讲讲怎么使用Linux安装这个库。
    首先你要有一个Linux的子系统或者虚拟系统之类的,windows子系统的安装方法在我之前的博文里面有介绍过需要的小伙伴请看这里,安装好WSL之后,我们需要准备一个Anaconda大礼包,Anacodna我们需要下载X86架构的。

在这里插入图片描述
Anaconda安装需要使用到Linux中的Bash命令,在这里我需要郑重说明一下,比如windows中路径为:

C:\Users\Administrator\Downloads\Anaconda3-2021.11-Linux-x86_64.sh

那么在WSL子系统中的对应路径就是:

/mnt/c/Users/Administrator/Downloads/Anaconda3-2021.11-Linux-x86_64.sh

Linux中的/mnt/c/等价于windows中的C:\且Linux中不能使用\作为各级目录分割

 bash /mnt/c/Users/Administrator/Downloads/Anaconda3-2021.11-Linux-x86_64.sh

在这里插入图片描述
接下来一路按照他的提示走就完事了!!

接着输入

conda install -c conda-forge xesmf

安装好之后,可能还需要安装xarray,cartopy

conda install xarray
conda install cartopy

二、代码剖析部分

  1. 导入相关库
import xarray as xr
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import xesmf as xe
import cmaps
  1. 读取文件
ds = xr.open_dataset('/mnt/d/CSDN测试数据集/heff.nc')
# print(ds.keys())
print(ds.longitude.data)
  1. 对原始数据进行插值
ds_out = xr.Dataset(coords = {"lat": np.arange(-90, 90, 1.0), "lon": ("lon", np.arange(0,360, 1))}) # 定义输出坐标系信息,我这里为随测试的,分辨率是1°的
regridder = xe.Regridder(ds_in = ds, ds_out = ds_out, method = "bilinear") # 参数ds_in要求输入原始的Dataset,参数ds_out是输出坐标系信息, 参数method 为插值方法,我这里使用的是线性插值方法
ds = regridder(ds) # ok 这个就是插值完成了
  1. 按照季节对数据求平均值并获取对应数据
ds = ds.sel(lat=slice(66,90)).groupby('time.season').mean() # 首先提取北纬66至90至今的数据,接着将数据以季节进行分割
lat1  = np.array(ds['lat'].sel(lat=slice(66,90)).values)
lon1  = np.array(ds['lon'].values)
DJF = ds.sel(season='DJF')['sivol'].values
JJA = ds.sel(season='JJA')['sivol'].values
MAM = ds.sel(season='MAM')['sivol'].values
SON = ds.sel(season='SON')['sivol'].values

三、绘制极射赤道投影图

由于我们出的是四季的图,也就是说有四张,那么我就先将一些重复的代码封装成一个函数

def maxax(ax):
    import matplotlib.path as mpath #导入matplotlib.path模块
    ax.gridlines() #添加网格线
    leftlon, rightlon, lowerlat, upperlat = (-180,180,60,90) #设置经纬度范围
    img_extent = [leftlon, rightlon, lowerlat, upperlat]
    ax.set_extent(img_extent, ccrs.PlateCarree()) #设置经纬度范围和投影坐标
    ax.add_feature(cfeature.COASTLINE.with_scale('50m')) #添加海岸线
    theta = np.linspace(0, 2*np.pi, 100) #将图片设置成圆形
    center, radius = [0.5, 0.5], 0.5 ##将图片设置成圆形
    verts = np.vstack([np.sin(theta), np.cos(theta)]).T ##将图片设置成圆形
    circle = mpath.Path(verts * radius + center) ##将图片设置成圆形
    ax.set_boundary(circle, transform=ax.transAxes) #将图片设置成圆形

接着就是出图的核心代码

fig = plt.figure(figsize=(30,12))
ax1 = plt.subplot(2, 2, 1, projection=ccrs.NorthPolarStereo()) #设置子图
ax2 = plt.subplot(2, 2, 2, projection=ccrs.NorthPolarStereo()) #设置子图
ax3 = plt.subplot(2, 2, 3, projection=ccrs.NorthPolarStereo()) #设置子图
ax4 = plt.subplot(2, 2, 4, projection=ccrs.NorthPolarStereo()) #设置子图
maxax(ax1)
maxax(ax2)
maxax(ax3)
maxax(ax4)
ax1.set_title('DJF',fontsize=20) #给每个子图添加标题
ax2.set_title('MAM',fontsize=20) #给每个子图添加标题
ax3.set_title('JJA',fontsize=20) #给每个子图添加标题
ax4.set_title('SON',fontsize=20) #给每个子图添加标题
level = np.arange(-10,10.1,1) #色带显示范围为
c7 = ax1.contourf(lon,lat,BCC_DJF_s,levels = level, extend = 'both',transform=ccrs.PlateCarree(), cmap=plt.cm.RdBu_r) 
ax2.contourf(lon,lat,BCC_MAM_s,levels = level, extend = 'both',transform=ccrs.PlateCarree(), cmap=plt.cm.RdBu_r)
ax3.contourf(lon,lat,BCC_JJA_s,levels = level, extend = 'both',transform=ccrs.PlateCarree(), cmap=plt.cm.RdBu_r)
ax4.contourf(lon,lat,BCC_SON_s,levels = level,extend = 'both',transform=ccrs.PlateCarree(), cmap=plt.cm.RdBu_r)

# 下面的是设置colorbar位置,以及将colorbar设置为横向
l = 0.22
b = 0.005
w = 0.6
h = 0.02
rect = [l,b,w,h] 
cbar_ax = fig.add_axes(rect) 
fig.subplots_adjust(bottom=0.2)     
c=plt.colorbar(c7, cax=cbar_ax,orientation='horizontal', aspect=20, pad=0.1)
c.ax.tick_params(labelsize=14)

在这里插入图片描述

四、 完整代码

import xarray as xr
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import xesmf as xe
import cmaps

def maxax(ax):
    import matplotlib.path as mpath
    ax.gridlines()
    leftlon, rightlon, lowerlat, upperlat = (-180,180,60,90)
    img_extent = [leftlon, rightlon, lowerlat, upperlat]
    ax.set_extent(img_extent, ccrs.PlateCarree())
    ax.add_feature(cfeature.COASTLINE.with_scale('50m'))
    theta = np.linspace(0, 2*np.pi, 100)
    center, radius = [0.5, 0.5], 0.5
    verts = np.vstack([np.sin(theta), np.cos(theta)]).T
    circle = mpath.Path(verts * radius + center)
    ax.set_boundary(circle, transform=ax.transAxes)

ds = xr.open_dataset('/mnt/d/heff.H1978-2014.nc')
# print(ds.keys())
print(ds.longitude.data)

ds_out = xr.Dataset(coords = {"lat": np.arange(-90, 90, 1.0), "lon": ("lon", np.arange(0,360, 1))}) 
regridder = xe.Regridder(ds_in = ds, ds_out = ds_out, method = "bilinear")
ds = regridder(ds)

ds = ds.sel(lat=slice(66,90)).groupby('time.season').mean() 
lat  = np.array(ds['lat'].sel(lat=slice(66,90)).values)
lon  = np.array(ds['lon'].values)
DJF = ds.sel(season='DJF')['h_ice'].values
JJA = ds.sel(season='JJA')['h_ice'].values
MAM = ds.sel(season='MAM')['h_ice'].values
SON = ds.sel(season='SON')['h_ice'].values

fig = plt.figure(figsize=(16,12))
ax1 = plt.subplot(2, 2, 1, projection=ccrs.NorthPolarStereo())
ax2 = plt.subplot(2, 2, 2, projection=ccrs.NorthPolarStereo())
ax3 = plt.subplot(2, 2, 3, projection=ccrs.NorthPolarStereo())
ax4 = plt.subplot(2, 2, 4, projection=ccrs.NorthPolarStereo())
maxax(ax1)
maxax(ax2)
maxax(ax3)
maxax(ax4)
ax1.set_title('DJF',fontsize=20)
ax2.set_title('MAM',fontsize=20)
ax3.set_title('JJA',fontsize=20)
ax4.set_title('SON',fontsize=20)
level = np.arange(-2,5.1,0.2)
c7 = ax1.contourf(lon,lat,DJF,levels = level, extend = 'both',transform=ccrs.PlateCarree(), cmap=plt.cm.RdBu_r)
ax2.contourf(lon,lat,MAM,levels = level, extend = 'both',transform=ccrs.PlateCarree(), cmap=plt.cm.RdBu_r)
ax3.contourf(lon,lat,JJA,levels = level, extend = 'both',transform=ccrs.PlateCarree(), cmap=plt.cm.RdBu_r)
ax4.contourf(lon,lat,SON,levels = level,extend = 'both',transform=ccrs.PlateCarree(), cmap=plt.cm.RdBu_r)

l = 0.22
b = 0.005
w = 0.6
h = 0.02
rect = [l,b,w,h] 
cbar_ax = fig.add_axes(rect) 
fig.subplots_adjust(bottom=0.2)     
c=plt.colorbar(c7, cax=cbar_ax,orientation='horizontal', aspect=20, pad=0.1)
c.ax.tick_params(labelsize=14)
<think>好的,用户想要了解如何将NC文件的经纬度格网换为极地投影。首先,我需要回忆一下这方面的知识,确保步骤正确。 首先,NC文件通常是NetCDF格式,存储的是科学数据,比如气象或海洋数据,这些数据通常以经纬度网格的形式存在。极地投影,比如南或北投影,常见的有Lambert方位等积投影或者赤面投影换的关键在于将经纬度坐标换为目标投影坐标系统,可能进行重采样。 接下来,我需要考虑几个步骤:数据读取、投影定义、坐标换、数据重采样和结果输出。用户可能需要使用一些工具,比如Python的xarray、GDAL或者NCO工具包。这里可能需要具体说明使用哪种工具,但通常Python在科学数据处理中比较常用。 然后,详细步骤方面,首先是读取NetCDF文件,使用xarray库可以方便地处理。然后定义目标投影,比如使用Cartopy库中的投影参数。接着,需要将每个经纬度点换为投影后的坐标,这里可能需要计算新的x和y坐标。不过直接换可能会导致数据不规则,所以可能需要重采样到规则的网格上,比如使用插值方法。 同时,需要注意处理可能的数据缺失或无效值,尤其是在极地地区,可能存在大量缺失数据。另外,换后的数据需要保持正确的元数据,比如坐标信息和投影参数,以便后续分析。 用户可能还需要了解不同投影之间的差异,选择适合自己需投影方式。例如,Lambert方位等积投影适合保持面积,而赤面投影可能适合中纬度地区的可视化。 另外,可能遇到的问题包括计算量大,尤其是高分辨率数据,这时候需要优化代码或者使用行处理。还有可能遇到坐标系统换的错误,需要检查投影参数是否正确。 总结一下,步骤大致是:读取数据、定义投影坐标、重采样数据、输出结果。需要结合具体工具和库来实现,同时注意数据精度和处理效率。</think>将NetCDF(NC文件中的经纬度格网数据换为极地投影(如南/北投影)需要以下关键步骤: --- ### **1. 明确目标投影类型** 常见极地投影类型: - **赤面投影(Polar Stereographic)** $$ x = \rho \sin(\lambda - \lambda_0), \quad y = -\rho \cos(\lambda - \lambda_0) $$ 其中 $\rho = R \cot(\phi_c/2) \tan(\pi/4 - \phi/2)$ - **Lambert方位等积投影** --- ### **2. 数据预处理** - **读取NC文件** 使用Python库(如`xarray`)读取数据: ```python import xarray as xr ds = xr.open_dataset('input.nc') ``` - **提取经纬度变量** 检查维度名称(如`lat`, `lon`)及单位(需换为弧度制)。 --- ### **3. 定义投影坐标系** 使用`cartopy.crs`定义目标投影: ```python import cartopy.crs as ccrs # 示例:北投影(中央经线为0°,标准纬线70°N) target_crs = ccrs.NorthPolarStereo(central_longitude=0, true_scale_latitude=70) ``` --- ### **4. 坐标换** - **计算投影坐标** 将经纬度点$(lon, lat)$换为投影坐标系$(x, y)$: ```python import numpy as np transformer = target_crs.transform_points(ccrs.PlateCarree(), lon, lat) x, y = transformer[..., 0], transformer[..., 1] ``` - **处理边界问题** 极地投影可能包含无效区域(如南投影中的赤道以南数据),需设置掩膜。 --- ### **5. 数据重采样(可选)** 若需规则网格,使用插值方法(如双线性插值): ```python from scipy.interpolate import griddata grid_x, grid_y = np.meshgrid(new_x_coords, new_y_coords) resampled_data = griddata((x.flatten(), y.flatten()), data.flatten(), (grid_x, grid_y), method='linear') ``` --- ### **6. 输出结果** 保存为新的NetCDF文件: ```python ds_new = xr.Dataset( {'data': (['y', 'x'], resampled_data)}, coords={'x': grid_x[0,:], 'y': grid_y[:,0]} ) ds_new.to_netcdf('output_polar.nc') ``` --- ### **注意事项** - **计算效率**:高分辨率数据需分块处理或使用Dask行 - **元数据保留**:添加`grid_mapping`属性描述投影参数 - **可视化验证**:用`matplotlib`+`cartopy`绘制结果图检查对齐 实际代码需根据具体数据格式调整,建议参考`xarray`、`cartopy`和`pyproj`的官方文档。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卷心没有菜

你若晌饭便是义父!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值