2d非结构化网格数据的插值

时间:2016-03-13 08:28:22

标签: python matplotlib scipy interpolation

我有一些data(x,y,z)位于非结构化网格上,我想插入数据以用于可视化目的。

我已经尝试过scipy.interpolate.griddata,插值假定每个地方都有相同的值。之后我尝试scipy.interpolate.Rbf,但这会给我带来内存错误(请参阅下面的代码)。

是否有其他方法或其他选项可以改善结果?

结果 - >

result

我的代码

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata, Rbf

x, y, z = np.loadtxt('stackoverflow_example-data')
# griddata
points = np.reshape(np.array([x, y]),(z.size, 2))
grid_x, grid_y = np.mgrid[x.min():x.max():1000j,y.min():y.max():1000j]
counts_I_grid_1 = griddata(points, z, (grid_x, grid_y), method='nearest')
counts_I_grid_2 = griddata(points, z, (grid_x, grid_y), method='linear', fill_value=0)
counts_I_grid_3 = griddata(points, z, (grid_x, grid_y), method='cubic', fill_value=0) 

# Rbf -- fails due to memory error
#rbf = Rbf(x,y,z)
#counts_I_Rbf = rbf(grid_x,grid_y)
  

追踪(最近一次通话):         文件“/path/code.py”,第14行,in           rbf = Rbf(x,y,z)         在 init 中输入文件“/[...]/python3.4/site-packages/scipy/interpolate/rbf.py”,第198行           r = self._call_norm(self.xi,self.xi)         在_call_norm中输入文件“/[...]/python3.4/site-packages/scipy/interpolate/rbf.py”,第222行           return self.norm(x1,x2)         在_euclidean_norm中输入文件“/[...]/python3.4/site-packages/scipy/interpolate/rbf.py”,第114行           return sqrt(((x1 - x2)** 2).sum(axis = 0))       的MemoryError

# plot the result
fig = plt.figure()

ax1 = plt.subplot(2,2,1)
plt.title('Data')
plt.gca().set_aspect((x.max() - x.min()) / (y.max() - y.min()))
plt.scatter(x, y, c=z, s=2, edgecolor='', marker=',')
plt.colorbar(ax=ax1)
plt.xlim(x.min(), x.max())
plt.ylim(y.min(), y.max())
plt.xticks([20.7,20.9,21.1,21.3])
plt.ticklabel_format(useOffset=False)

ax2 = plt.subplot(2,2,2)
plt.title('nearest')
plt.imshow(counts_I_grid_1.T, origin='lower',
           extent=(x.min(), x.max(), y.min(), y.max()),
           aspect=(x.max() - x.min()) / (y.max() - y.min()),
           vmin=0,vmax=36)
plt.colorbar(ax=ax2)
plt.xticks([20.7,20.9,21.1,21.3])
plt.ticklabel_format(useOffset=False)

ax2 = plt.subplot(2,2,3)
plt.title('linear')
plt.imshow(counts_I_grid_2.T, origin='lower',
           extent=(x.min(), x.max(), y.min(), y.max()),
           aspect=(x.max() - x.min()) / (y.max() - y.min()),
           vmin=0,vmax=36)
plt.colorbar(ax=ax2)
plt.xticks([20.7,20.9,21.1,21.3])
plt.ticklabel_format(useOffset=False)

ax2 = plt.subplot(2,2,4)
plt.title('cubic')
plt.imshow(counts_I_grid_3.T, origin='lower',
           extent=(x.min(), x.max(), y.min(), y.max()),
           aspect=(x.max() - x.min()) / (y.max() - y.min()),
           vmin=0,vmax=36)
plt.colorbar(ax=ax2)
plt.xticks([20.7,20.9,21.1,21.3])
plt.ticklabel_format(useOffset=False)
plt.tight_layout()
plt.show()

1 个答案:

答案 0 :(得分:2)

你的问题是由于一个足够危险的微妙错误,我认为值得给出完整答案。

考虑这一行:

points = np.reshape(np.array([x, y]),(z.size, 2))

由于您的输入数组是1d,因此您尝试将[x,y]转换为形状“(某事,2)”。请注意,说

是有效的
points = np.reshape(np.array([x, y]),(-1, 2))

让numpy为你推断缺失的维度,这仍然不是你想要的。构造二维数组时

np.array([x, y])

你要逐行定义一个矩阵,从而创建一个形状为“(2,something)”的数组。当你在它上面调用reshape时,默认情况下会逐行读取元素,因为numpy以行主要顺序存储数组(如C / C ++,与fortran和MATLAB不同)。这意味着生成的双列数组将首先包含所有x值,然后包含所有y值,而不是每行包含(x,y)对。

您实际要做的是交换数组的维度,而不触及其结构。这意味着您必须转置矩阵。这意味着您必须使用

points = np.array([x, y]).T
# or np.transpose([x,y])

代替。请注意,虽然它与原始版本具有相同的shape,但它具有正确顺序的元素:

In [320]: np.reshape(np.array([x,y]),(-1,2))
Out[320]: 
array([[  20.7     ,   20.702   ],
       [  20.704   ,   20.706   ],
       [  20.708   ,   20.71    ],
       ..., 
       [ 852.356964,  852.356964],
       [ 852.356964,  852.356964],
       [ 852.356964,  852.356964]])

In [321]: np.array([x,y]).T
Out[321]: 
array([[  20.7     ,  852.357235],
       [  20.702   ,  852.357235],
       [  20.704   ,  852.357235],
       ..., 
       [  21.296   ,  852.356964],
       [  21.298   ,  852.356964],
       [  21.3     ,  852.356964]])

这将解决您的样本x/y点与z之间的不一致,并会产生预期结果。根据我的经验,reshape - 几乎从未被要求过。通常,您需要将ndarray展平为1d,但最好是给定数组的ravel()方法。

结果作为证明:左,你的原始立方插值;是的,修复了points的版本:

before after

请注意,作为@MaxNoe suggested,我将插值网格大小减小到200x200。正如他所暗示的那样,Rbf的内存错误很可能源于这么多的插值点。