简体   繁体   English

matplotlib稀疏(常规)数据的轮廓显示了人工制品

[英]matplotlib contour of sparse (regular) data shows artefacts

I would like to contour data that are quite sparse and where a maximum is going diagonally through the picture; 我想要对非常稀疏的数据进行轮廓分析,并且最大值在图片的对角线上; the matplotlib contour function invents minima between the sampled maxima. matplotlib轮廓函数发现采样的最大值之间的最小值。

Starting with the densely sampled case where everything looks as expected: 从密集采样的情况开始,一切看起来都像预期的那样:

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

x_1D = np.linspace(0., 10., 100)
y_1D = np.linspace(0., 10., 100)
x, y = np.meshgrid(x_1D, y_1D)
z = np.empty_like(x)
def peak(y, y0):
    return np.exp(-(y-y0)**2)
for i in range(x_1D.size):
    z[:,i] = peak(y_1D, i/x_1D.size*y_1D.max())

fig, ax = plt.subplots(ncols=3)

ax[0].set_title('measured data')
ax[0].scatter(x, y, marker='s', c=z, cmap=plt.cm.jet, s=25)

ax[1].set_title('contour')
ax[1].contourf(x, y, z, levels=14, cmap=plt.cm.jet)

# define grid
xi = np.linspace(x_1D.min()-0.1, x_1D.max()+0.1, 1000)
yi = np.linspace(y_1D.min()-0.1, y_1D.max()+0.1, 1000)

# grid the data
triang = tri.Triangulation(x.flatten(), y.flatten())
interpolator = tri.LinearTriInterpolator(triang, z.flatten())
Xi, Yi = np.meshgrid(xi, yi)
zi = interpolator(Xi, Yi)

ax[2].set_title('interpolated')
ax[2].contourf(xi, yi, zi, levels=14, cmap=plt.cm.jet)

plt.show()

yields 产量

在此输入图像描述

When x is sampled less by a factor 10, ie x_1D = np.linspace(0., 10., 10) , minima appear between the sampled maxima in the contour plot. 当x被采样得小10倍,即x_1D = np.linspace(0., 10., 10) ,最小值出现在等高线图中的采样最大值之间。

在此输入图像描述

Is there a way how to avoid this artefact and make the contour of the sparsely sampled data look like the one of the densely sampled data? 有没有办法如何避免这种假象,并使稀疏采样数据的轮廓看起来像密集采样数据之一?

EDIT: Thanks for the answer that works very nicely on the example I provided. 编辑:感谢您提供的示例非常好的答案。 Unfortunately, I have simplified the problem too far. 不幸的是,我把问题简化得太过分了。 Rather than talking about one diagonal line, I should have enquired about an arbitrary number of peaks moving in arbitrary directions through the picture; 我不应该谈论一条对角线,而应该询问在图片中任意方向移动的任意数量的峰值; eg replace the peak-generation by 例如,替换峰值生成

z = np.zeros_like(x)
def peak(y, y0):
    return np.exp(-(y-y0)**2)
for i in range(x_1D.size):
    z[:,i] += peak(y_1D, np.cos(i/x_1D.size*np.pi)*y_1D.max()*0.05+y_1D.max()*0.8)
for i in range(x_1D.size):
    z[:,i] += peak(y_1D, np.sin(i/x_1D.size*np.pi/2.)*y_1D.max()*0.5)

resulting in 导致 在此输入图像描述

The main issue with your approach is that the triangulation algorithm doesn't know that the peaks should be connecting to eachother between the "x-slices" (your line of dense data points for a constant x). 您的方法的主要问题是三角测量算法不知道峰值应该在“x切片”(您的常数x的密集数据点线)之间相互连接。

Simplifying a bit, the triangulation algorithm will look at the neighbours in the x and y direction and connect to those. 稍微简化一下,三角测量算法将查看x和y方向上的邻居并连接到那些。 Then, when trying to interpolate using this triangulation, the points between the peaks will be roughly an average of the nearest points in the x direction and hence the minima will appear. 然后,当尝试使用这种三角测量进行插值时,峰值之间的点将大致是x方向上的最近点的平均值,因此将出现最小值。 The best solution is to make your own triangulation, with the peaks connected directly. 最好的解决方案是进行自己的三角测量,峰值直接连接。

Fortunately, we can actually hack the triangulation to make it connect to the peaks by shifting the coordinates in the y direction such that the peaks are all aligned horizontally. 幸运的是,我们实际上可以破解三角测量,通过在y方向上移动坐标使其连接到峰值,使得峰值全部水平对齐。 This works because the triangulation algorithm uses the coordinates that you pass it. 这是因为三角测量算法使用您传递的坐标。 In your example this is easy to accomplish because we can just apply the simple shift y_s = y - x . 在您的示例中,这很容易实现,因为我们可以应用简单的移位y_s = y - x In general you would have to get the equation for your peak (call it y_p(x) ) and then subtract that from y to get the y_s . 一般来说,你必须得到你的峰值方程(称之为y_p(x) )然后从y减去它以得到y_s

Now that you have a shifted triangulation, you can make a new denser grid (like you did) and apply the same shift. 既然你有一个移动的三角测量,你可以制作一个新的更密集的网格(就像你做的那样)并应用相同的移位。 Then, you interpolate in the shifted mesh with the shifted dense grid to get the z values correctly interpolated. 然后,使用移位的密集网格在移位的网格中进行插值,以获得正确插值的z值。 Finally, you un-shift the dense grid to get the correct y values and plot it. 最后,您取消移动密集网格以获得正确的y值并绘制它。

Below is the code of applying this concept to your code and the final result. 下面是将此概念应用于您的代码和最终结果的代码。 As you can see. 如你看到的。 It works quite well for this case. 它适用于这种情况。

结果有Shift

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

def peak(y, y0):
    return np.exp(-(y-y0)**2)

x_1D = np.linspace(0., 10., 10)
y_1D = np.linspace(0., 10., 100)
x, y = np.meshgrid(x_1D, y_1D)
z = np.empty_like(x)

for i in range(x_1D.size):
    z[:,i] = peak(y_1D, i/x_1D.size*y_1D.max())

fig, ax = plt.subplots(ncols=4)

ax[0].set_title('measured data')
ax[0].scatter(x, y, marker='s', c=z, cmap=plt.cm.jet, s=25)

ax[1].set_title('contour')
ax[1].contourf(x, y, z, levels=14, cmap=plt.cm.jet)

# define output grid
xi_1D = np.linspace(x_1D.min()-0.1, x_1D.max()+0.1, 1000)
yi_1D = np.linspace(y_1D.min()-0.1, y_1D.max()+0.1, 1000)
xi, yi = np.meshgrid(xi_1D, yi_1D)

# Old Linear Interpolation
triang = tri.Triangulation(x.flatten(), y.flatten())
interpolator = tri.LinearTriInterpolator(triang, z.flatten())
zi = interpolator(xi, yi)

ax[2].set_title('interpolated')
ax[2].contourf(xi, yi, zi, levels=14, cmap=plt.cm.jet)

# === SHIFTED LINEAR INTERPOLATION ===

# make shifted interpolating mesh for the data
y_s=y-x
triang_s = tri.Triangulation(x.flatten(), y_s.flatten())
interpolator_s = tri.LinearTriInterpolator(triang_s, z.flatten())

# interpolate in the shifted state
yi_s = yi-xi
zi_s = interpolator_s(xi, yi_s)

# unshift the fine mesh
yi_us = yi_s+xi

ax[3].set_title('interpolated (shifted)')
ax[3].contourf(xi, yi_us, zi_s, levels=14, cmap=plt.cm.jet)


plt.show()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM