繁体   English   中英

重新网格化常规 netcdf 数据

[英]Regridding regular netcdf data

我有一个包含全球海面温度的 netcdf 文件。 使用 matplotlib 和 Basemap,我设法使用以下代码制作了此数据的地图:

from netCDF4 import Dataset
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap

filename = '/Users/Nick/Desktop/SST/SST.nc'
fh = Dataset(filename, mode='r')

lons = fh.variables['LON'][:]
lats = fh.variables['LAT'][:]
sst = fh.variables['SST'][:].squeeze()

fig = plt.figure()

m = Basemap(projection='merc', llcrnrlon=80.,llcrnrlat=-25.,urcrnrlon=150.,urcrnrlat=25.,lon_0=115., lat_0=0., resolution='l')

lon, lat = np.meshgrid(lons, lats)
xi, yi = m(lon, lat)

cs = m.pcolormesh(xi,yi,sst, vmin=18, vmax=32)

m.drawmapboundary(fill_color='0.3')
m.fillcontinents(color='0.3', lake_color='0.3')
cbar = m.colorbar(cs, location='bottom', pad="10%", ticks=[18., 20., 22., 24., 26., 28., 30., 32.])
cbar.set_label('January SST (' + u'\u00b0' + 'C)')
plt.savefig('SST.png', dpi=300)

问题是数据的分辨率非常高(9km 网格),这使得生成的图像非常嘈杂。 我想将数据放在较低分辨率的网格(例如 1 度)上,但我正在努力弄清楚如何做到这一点。 我遵循了一个可行的解决方案,通过将下面的代码插入到我上面的示例中来尝试使用 matplotlib griddata 函数,但它导致“ValueError:条件必须是一维数组”。

xi, yi = np.meshgrid(lons, lats)

X = np.arange(min(x), max(x), 1)
Y = np.arange(min(y), max(y), 1)

Xi, Yi = np.meshgrid(X, Y)

Z = griddata(xi, yi, z, Xi, Yi)

我是 Python 和 matplotlib 的相对初学者,所以我不确定我做错了什么(或者更好的方法可能是什么)。 任何建议表示赞赏!

如果您使用例如双线性插值将数据重新网格化为更粗糙的纬度/经度网格,这将导致更平滑的场。

NCAR ClimateData 指南对重新网格有一个很好的介绍(一般的,不是特定于 Python 的)。

可用于 Python 的重新网格化例程的最强大实现是,据我所知,地球系统建模框架 (ESMF) Python 接口 (ESMPy) 如果这对您的应用程序来说有点过于复杂,您应该查看

  1. 关于重新网格化的 EarthPy教程(例如使用PyresamplecKDTreeBasemap )。
  2. 将您的数据转换为Iris立方体并使用Iris 的重新网格化功能

也许从使用 Basemap查看EarthPy 重新网格化教程开始,因为您已经在使用它了。

在您的示例中执行此操作的方法是

from mpl_toolkits import basemap
from netCDF4 import Dataset

filename = '/Users/Nick/Desktop/SST/SST.nc'
with Dataset(filename, mode='r') as fh:
   lons = fh.variables['LON'][:]
   lats = fh.variables['LAT'][:]
   sst = fh.variables['SST'][:].squeeze()

lons_sub, lats_sub = np.meshgrid(lons[::4], lats[::4])

sst_coarse = basemap.interp(sst, lons, lats, lons_sub, lats_sub, order=1)

这对您的 SST 数据执行双线性插值( order=1 )到子采样网格(每四个点)。 之后你的情节看起来会更粗粒度。 如果您不喜欢那样,请使用例如插值回原始网格

sst_smooth = basemap.interp(sst_coarse, lons_sub[0,:], lats_sub[:,0], *np.meshgrid(lons, lats), order=1)

我通常通过拉普拉斯滤波器运行我的数据以进行平滑。 也许您可以尝试下面的功能,看看它是否对您的数据有帮助。 该函数可以在有或没有掩码的情况下调用(例如海洋数据点的陆地/海洋掩码)。 希望这可以帮助。

# Laplace filter for 2D field with/without mask
# M = 1 on - cells used
# M = 0 off - grid cells not used
# Default is without masking

import numpy as np
def laplace_X(F,M):
    jmax, imax = F.shape
    # Add strips of land
    F2 = np.zeros((jmax, imax+2), dtype=F.dtype)
    F2[:, 1:-1] = F
    M2 = np.zeros((jmax, imax+2), dtype=M.dtype)
    M2[:, 1:-1] = M

    MS = M2[:, 2:] + M2[:, :-2]
    FS = F2[:, 2:]*M2[:, 2:] + F2[:, :-2]*M2[:, :-2]

    return np.where(M > 0.5, (1-0.25*MS)*F + 0.25*FS, F)

def laplace_Y(F,M):
    jmax, imax = F.shape

    # Add strips of land
    F2 = np.zeros((jmax+2, imax), dtype=F.dtype)
    F2[1:-1, :] = F
    M2 = np.zeros((jmax+2, imax), dtype=M.dtype)
    M2[1:-1, :] = M

    MS = M2[2:, :] + M2[:-2, :]
    FS = F2[2:, :]*M2[2:, :] + F2[:-2, :]*M2[:-2, :]

    return np.where(M > 0.5, (1-0.25*MS)*F + 0.25*FS, F)


# The mask may cause laplace_X and laplace_Y to not commute
# Take average of both directions

def laplace_filter(F, M=None):
    if M == None:
        M = np.ones_like(F)
    return 0.5*(laplace_X(laplace_Y(F, M), M) +
                laplace_Y(laplace_X(F, M), M))

也回答有关scipy.interpolate.griddata的原始问题:

仔细查看该函数的参数规范(例如在SciPy 文档中)并确保您的输入数组具有正确的形状 你可能需要做类似的事情

import numpy as np
points = np.vstack([a.flat for a in np.meshgrid(lons,lats)]).T # (n,D)
values = sst.ravel() # (n)

等等。

如果您在 Linux 上工作,则可以使用 nctoolkit ( https://nctoolkit.readthedocs.io/en/latest/ ) 实现此目的。

您尚未说明数据的 latlon 范围,因此我假设它是一个全局数据集。 重新网格化到 1 度分辨率需要以下内容:

import nctoolkit as nc
filename = '/Users/Nick/Desktop/SST/SST.nc'
data = nc.open_data(filename)

data.to_latlon(lon = [-179.5, 179.5], lat = [-89.5, 89.5], res = [1,1])
# visualize the data
data.plot()

看看这个带有 xarray 的例子...使用ds.interp方法并指定新的纬度和经度值。

http://xarray.pydata.org/en/stable/interpolation.html#example

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM