Matplotlib 二维图形插值展示

3
我正在尝试创建一个绘制水平面上温度梯度的图表。我能够得到颜色,但它没有按照我需要的方式进行插值。这个问题对创建图表很有帮助。看起来当生成图表时,点的权重不是相等的。这个链接是当前图表的样子。它应该像色条一样,因为顶部两个点是23.7,底部两个点是23.4。我使用的代码是: enter image description here
   xi, yi = np.linspace(xm, xM, 500), np.linspace(ym, yM, 500)
   xi, yi = np.meshgrid(xi, yi)
   xo=[0, 0, 2, 2]
   yo=[0, 2, 0, 2]
   ao=[23.4, 23.7, 23.4, 23.7]
   rbf = scipy.interpolate.Rbf(xo, yo, ao, function='linear')
   ai = rbf(xi, yi)

   plt.xlabel('X')
   plt.ylabel('Y')

   plt.imshow(ai, vmin=am, vmax=aM, origin='lower', extent=[xm, xM, ym, yM])

   plt.scatter(xo, yo, c=ao)
   plt.colorbar()
   plt.show()

2
发生的原因是您的z值的绝对值大约比x和y值大10倍。这会导致在求解适当权重时出现数值稳定性问题。Scipy应该进行一些合理性检查并“白化”(又称重新缩放)输入数据,但它没有这样做。在插值之前,您应该能够通过对ao进行简单的线性重新缩放,然后对结果进行反向操作来解决问题。 - Joe Kington
1
我的猜测是你的“vmin”和“vmax”值是错误的,我尝试将它们设置为“ao.min()”和“ao.max()”,结果如下:http://i.imgur.com/8Om1YdG.png - user1767344
我之前的评论有误,正确应该是 ai.min()ai.max()。这很重要。或者你可以直接跳过它们,Matplotlib 会自动修复。 - user1767344
@JoeKington 我该怎么做? - user2386081
2个回答

6

关于我之前的评论,进一步解释:

问题出在您的a值的绝对值比xy值高大约10倍。

这导致了在求解适当权重时出现数值稳定性问题。Scipy可能应该进行一些合理性检查并“白化”(即重新缩放)输入数据,但它没有这么做。

由于权重不正确,插值值低于最小输入a值(这在线性RBF中不应该发生)。 这导致您指定的vminvmax值“裁剪”了网格,正如@user1767344所注意到的那样。 下面显示了“未裁剪”的版本,但如果您指定类似的vminvmax,则会看到与原始示例相同的结果。

例如:

import numpy as np
import scipy.interpolate
import matplotlib.pyplot as plt

def main():
    x = np.array([0, 0, 2, 2])
    y = np.array([0, 2, 0, 2])
    a = np.array([23.4, 23.7, 23.4, 23.7])
    xi, yi = np.mgrid[x.min():x.max():500j, y.min():y.max():500j]

    a_orig = normal_interp(x, y, a, xi, yi)
    a_rescale = rescaled_interp(x, y, a, xi, yi)

    plot(x, y, a, a_orig, 'Not Rescaled')
    plot(x, y, a, a_rescale, 'Rescaled')
    plt.show()

def normal_interp(x, y, a, xi, yi):
    rbf = scipy.interpolate.Rbf(x, y, a)
    ai = rbf(xi, yi)
    return ai

def rescaled_interp(x, y, a, xi, yi):
    a_rescaled = (a - a.min()) / a.ptp()
    ai = normal_interp(x, y, a_rescaled, xi, yi)
    ai = a.ptp() * ai + a.min()
    return ai

def plot(x, y, a, ai, title):
    fig, ax = plt.subplots()

    im = ax.imshow(ai.T, origin='lower',
                   extent=[x.min(), x.max(), y.min(), y.max()])
    ax.scatter(x, y, c=a)

    ax.set(xlabel='X', ylabel='Y', title=title)
    fig.colorbar(im)

main()      

输入图像 输出图像

两者唯一的区别在于将输入和输出的a值线性重新缩放到0和1之间:

def normal_interp(x, y, a, xi, yi):
    rbf = scipy.interpolate.Rbf(x, y, a)
    ai = rbf(xi, yi)
    return ai

def rescaled_interp(x, y, a, xi, yi):
    a_rescaled = (a - a.min()) / a.ptp()
    ai = normal_interp(x, y, a_rescaled, xi, yi)
    ai = a.ptp() * ai + a.min()
    return ai

因为这是一种二维插值方法,所以结果并不完全“像色条”。如果你想让它这样,可以使用一维插值并平铺结果。或者,这是一个简单的三角插值方法(例如 griddata)适用的情况,并且应该会给出与一维结果相同的结果。(缺点是在其他情况下它可能不太“平滑”,但这总是一个权衡。)

2

或者,如果您已经安装了matplolib 1.3.0,您可以对数据进行三角化并使用一个细化/平滑函数:matplotlib.tri.UniformTriRefiner(它应该为任何a数据提供平滑轮廓,并且对于xy的线性函数是精确的)

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as mtri
import matplotlib.cm as cm

def main():
    x = np.array([0, 0, 2, 2])
    y = np.array([0, 2, 0, 2])
    a = np.array([23.4, 23.7, 23.4, 23.7])

    triang = mtri.Triangulation(x, y)
    refiner = mtri.UniformTriRefiner(triang)
    tri_refi, z_test_refi = refiner.refine_field(a, subdiv=4)

    plt.figure()
    plt.gca().set_aspect('equal')
    levels = np.arange(23.4, 23.7, 0.025)
    cmap = cm.get_cmap(name='terrain')
    plt.tricontourf(tri_refi, z_test_refi, levels=levels, cmap=cmap)
    plt.colorbar()

    plt.title("Triangulated")
    plt.show()

main() 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接