试图在规则间隔的网格上放置不规则间隔的纬度/经度数据

时间:2017-07-13 21:24:58

标签: python scipy interpolation matplotlib-basemap

我有一些卫星数据,我试图插入0.25度x 0.25度网格。

我正在尝试使用makeFibonacci,但我收到了意想不到的结果。

我只需要在卫星的扫描范围内进行插值。我不需要在全球范围内进行插值。

这是我的代码:

scipy.intepolate.griddata

当我在网格化之前绘制数据时,它看起来像这样: Before Gridding

网格化后,它看起来像这样: After Gridding

这是我正在使用的HDF文件: http://www.filedropper.com/2a2520150314987057

显然,生成的图像未正确插值。我该怎么做才能解决这个问题?

我的最终目标是拍摄数千个这些卫星条带,每个条带通过全球不同的路径,并将它们组合成一个数据集。网格化到较粗糙分辨率的要点是:1。减少所有数据的量;以及2.能够导出特定网格点的统计数据。另一件事:理想情况下,网格之外的点将在网格化后转换为NaN

2 个答案:

答案 0 :(得分:2)

正如我在评论中所指出的那样,问题在于您将数据放在非常狭窄的条带上,使您的数据伪1d。如果你试图"插入"从这个到全球,您实际上是根据几乎不存在的值进行外推,这解释了原始图中的噪声。

由于您在编辑中澄清了您只对在数据区域中进行插值感兴趣,因此我发现了另一种问题。沿着这条狭窄的经度 - 纬度点的固定规则网格对我来说是没有意义的。查看原始数据的pcolormesh图:

import numpy as np
from pyhdf.SD import SD,SDC
import matplotlib.pyplot as plt
import scipy.interpolate as interp

hdffile = 'your_file_name.hdf'

hdf = SD(hdffile, SDC.READ)
lon = hdf.select('Longitude')[:,:]
lat = hdf.select('Latitude')[:,:]
refl = hdf.select('correctZFactor')[:,:,70]/100

lon[lon<0] += 360 # shift longitude to contiguous block

fig,ax = plt.subplots()
ax.pcolormesh(lon,lat,refl,cmap='viridis')

original data

希望上面的情节表达了我的意思:尝试将这个域放在常规网格上对于我能想到的任何合理用途都没有用。特别是如果你认为给定经度的纬度宽度几乎接近你预期的0.25度分辨率。

所以我建议的是在经度上采用规则网格,并且对于每个经度,在域中采用纬度的规则网格。这意味着你的最终网格不是常规的,但它将是拓扑2d格子(就好像是由meshgrid生成的),因此它对绘图或其他后处理目的很有用。

为了做到这一点,我首先为每个经度构造两个插值器用于最小和最大纬度值,然后生成(lon,lat)插值网格,然后进行插值:

# these will be overwritten later
lat_from = lat[:,0]
lat_to = lat[:,-1]
lon_from = lon[:,0]
lon_to = lon[:,-1]

# create interpolators for starting and ending latitude vs longitude
# only use a subset of the 9k data points
step = 10
latminfun = interp.interp1d(lon_from[::step],lat_from[::step],fill_value='extrapolate')
latmaxfun = interp.interp1d(lon_to[::step],lat_to[::step],fill_value='extrapolate')

# create interpolating mesh: regular in longitude, locally regular in latitude
nlon = 360 # ~1 degree along longitude
nlat = 10 # 10 points along latitude for each longitude
lon_grid = np.linspace(lon.min(),lon.max(),nlon)[:,None]  # shape (nlon,1)
lat_from = latminfun(lon_grid) # lower side of the latitude grid
lat_to = latmaxfun(lon_grid)   # upper side of the latitude grid
x = np.linspace(0,1,nlat) # to perform linear interpolation in lat with
lat_grid = x*lat_to + (1-x)*lat_from # shape (nlon,nlat)

# now (lon_grid,lat_grid) broadcast together to a grid of shape (nlon,nlat)
refl_grid = interp.griddata((lon.ravel(),lat.ravel()),refl.ravel(),(lon_grid,lat_grid),method='nearest')
fig,ax = plt.subplots()
ax.pcolormesh(np.broadcast_to(lon_grid,lat_grid.shape),lat_grid,refl_grid,cmap='viridis')
# of course we could've overwritten lon_grid with the broadcast version

最终的情节在视觉上几乎与原始数据不同:

final plot

但它包含此直线经度 - 纬度网格上的最近邻居插值。我希望这是插入数据的最合理方式,而不知道有关您的计划的任何详细信息。

答案 1 :(得分:1)

我最终找到了使用KD树/最近邻居查找的解决方案

from scipy import spatial

kdtree = spatial.cKDTree(zip(lon.ravel(),lat.ravel()))
kdtree_gridPts = spatial.cKDTree(zip(lonGrid.ravel(),latGrid.ravel()))
closePts = kdtree_gridPts.query_ball_tree(kdtree, res/2)

reflGrid = ones_like(lonGrid)*nan
for ind,p in  enumerate(closePts):
    if len(p) > 0:
        reflGrid.ravel()[ind] = mean(refl.ravel()[p])

reflGrid = ma.masked_where(isnan(reflGrid), reflGrid)

基本上它是以每个网格框为中心的0.125(res / 2)圆内的所有点的平均值。至少,这是我认为它正在做的......

我还将我的域名缩小到我感兴趣的区域。它运行得非常快。

在下网格之前: Before Gridded

网格化后: After Gridding

预网格图片顶部的水平线实际上只是pcolormesh的一个神器