【问题标题】:Matplotlib 2D graph with interpolationMatplotlib 2D 插值图
【发布时间】:2013-07-10 17:54:56
【问题描述】:

我正在尝试创建一个绘图来显示水平面上的温度梯度。我能够降低颜色,但它没有按照我需要的方式进行插值。 This question 有助于创建情节。绘制绘图时,似乎这些点的权重不均等。 This 是图表当前的外观。它应该看起来像彩条,因为顶部两点是 23.7,底部两点是 23.4。我使用的代码是:

   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()

【问题讨论】:

  • 发生的情况是由于您的 z 值的绝对值比 x 和 y 值大约 10 倍。在求解适当的权重时,这会导致数值稳定性问题。 Scipy 应该做一些健全性检查并“白化”(又名重新缩放)输入数据,但它没有。您应该能够通过在插值之前对ao 进行简单的线性重新缩放然后对结果进行逆运算来解决您的问题。
  • 我的猜测是您的 'vmin' 和 'vmax' 值是错误的,我通过将它们设置为 'ao.min()' 和 'ao.max()' 进行了尝试,结果出来了像这样:i.imgur.com/8Om1YdG.png
  • 好吧,我在之前的评论中犯了一个错误。它应该是ai.min()ai.max() 这很重要。或者你可以直接跳过它们,matplotlib 会自动修复它。
  • @JoeKington 我该怎么做?

标签: python matplotlib


【解决方案1】:

扩展我之前的评论:

发生的情况是由于您的 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()      

两者之间的唯一区别只是在 0 和 1 之间线性重新调整输入和输出 a 值:

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

因为它是一种 2D 插值方法,所以结果并不完全“像颜色条”。如果您愿意,您可以使用一维插值并平铺结果。或者,在这种情况下,简单的三角插值方法(例如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() 
    

    【讨论】:

      猜你喜欢
      • 2015-12-10
      • 2017-08-26
      • 2017-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多