我有一个包含全球海面温度的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的相对初学者,所以我不确定我做错了什么(或者更好的方法可能是什么)。任何建议表示赞赏!
答案 0 :(得分:9)
如果您使用以下方法重新您的数据到更粗略的lat / lon网格双线性插值,这将导致更平滑的字段。
NCAR ClimateData指南有一个很好的introduction to regridding(一般,不是特定于Python)。
据我所知,对于Python而言,最强大的可用于Python的例程实现是Earth System Modeling Framework (ESMF) Python interface (ESMPy)。如果您的应用程序过于复杂,则应查看
也许从查看EarthPy regridding tutorial using Basemap开始,因为您已经在使用它了。
在您的示例中执行此操作的方法是
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)
答案 1 :(得分:0)
我通常通过拉普拉斯滤波器运行我的数据以进行平滑处理。也许您可以尝试下面的功能,看看它是否有助于您的数据。可以使用或不使用掩码调用该函数(例如,用于海洋数据点的陆地/海洋掩模)。希望这可以帮助。 Ť
# 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))
答案 2 :(得分:0)
要回答有关scipy.interpolate.griddata
的原始问题:
仔细查看该函数的参数规范(例如在SciPy documentation中),并确保输入数组具有正确的形状。您可能需要执行类似
的操作import numpy as np
points = np.vstack([a.flat for a in np.meshgrid(lons,lats)]).T # (n,D)
values = sst.ravel() # (n)
等
答案 3 :(得分:0)
如果您使用的是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()
答案 4 :(得分:-1)
使用xarray查看此示例...
使用ds.interp
方法并指定新的纬度和经度值。
http://xarray.pydata.org/en/stable/interpolation.html#example