使用Matplotlib平滑轮廓图中的数据

5
我正在使用Matplotlib创建等高线图。我有一个多维数组包含所有数据。它的长度为12,宽度约为2000。因此,它基本上是一个由12个列表组成的列表,每个列表长度为2000。我的等高线图已经可以工作了,但我需要平滑数据。我已经阅读了很多示例,但不幸的是,我没有数学背景理解这些内容。
那么,我该如何平滑这些数据呢?我有一个示例展示了我的图形样子和我想要的样子。这是我的图形: graph illustration 我希望它更像这样: my goal 我有什么方法可以使等高线图平滑,就像第二个图形一样吗?
我使用的数据来自XML文件。但是,我将展示数组的部分输出。由于数组中的每个元素大约有2000个项目,因此我只会展示摘录。
[27.899999999999999, 27.899999999999999, 27.899999999999999, 27.899999999999999,
 28.0, 27.899999999999999, 27.899999999999999, 28.100000000000001, 28.100000000000001,
 28.100000000000001, 28.100000000000001, 28.100000000000001, 28.100000000000001,
 28.100000000000001, 28.100000000000001, 28.0, 28.100000000000001, 28.100000000000001,
 28.0, 28.100000000000001, 28.100000000000001, 28.100000000000001, 28.100000000000001,
 28.100000000000001, 28.100000000000001, 28.100000000000001, 28.100000000000001,
 28.100000000000001, 28.100000000000001, 28.100000000000001, 28.100000000000001,
 28.100000000000001, 28.100000000000001, 28.100000000000001, 28.100000000000001,
 28.100000000000001, 28.100000000000001, 28.0, 27.899999999999999, 28.0,
 27.899999999999999, 27.800000000000001, 27.899999999999999, 27.800000000000001,
 27.800000000000001, 27.800000000000001, 27.899999999999999, 27.899999999999999, 28.0,
 27.800000000000001, 27.800000000000001, 27.800000000000001, 27.899999999999999,
 27.899999999999999, 27.899999999999999, 27.899999999999999, 28.0, 28.0, 28.0, 28.0,
 28.0, 28.0, 28.0, 28.0, 27.899999999999999, 28.0, 28.0, 28.0, 28.0, 28.0,
 28.100000000000001, 28.0, 28.0, 28.100000000000001, 28.199999999999999,
 28.300000000000001, 28.300000000000001, 28.300000000000001, 28.300000000000001,
 28.300000000000001, 28.399999999999999, 28.300000000000001, 28.300000000000001,
 28.300000000000001, 28.300000000000001, 28.300000000000001, 28.300000000000001,
 28.399999999999999, 28.399999999999999, 28.399999999999999, 28.399999999999999,
 28.399999999999999, 28.300000000000001, 28.399999999999999, 28.5, 28.399999999999999,
 28.399999999999999, 28.399999999999999, 28.399999999999999]

请注意,这只是一个摘录。数据的维度为12行1959列。列数会根据从XML文件导入的数据而变化。我可以在使用高斯滤波器后查看值,它们确实会改变。但是,这些更改不足以影响等值线图。

2个回答

14
你可以使用 gaussian_filter 来平滑你的数据:
import numpy as np
import matplotlib.pyplot as plt
import scipy.ndimage as ndimage

X, Y = np.mgrid[-70:70, -70:70]
Z = np.cos((X**2+Y**2)/200.)+ np.random.normal(size=X.shape)

# Increase the value of sigma to increase the amount of blurring.
# order=0 means gaussian kernel
Z2 = ndimage.gaussian_filter(Z, sigma=1.0, order=0)
fig=plt.figure()
ax=fig.add_subplot(1,2,1)
ax.imshow(Z)
ax=fig.add_subplot(1,2,2)
ax.imshow(Z2)
plt.show()

enter image description here

左侧显示原始数据,右侧显示高斯滤波后的数据。

以上大部分代码来自于Scipy Cookbook,它演示了使用手工制作的高斯核进行高斯平滑。由于Scipy已经内置了相同的功能,所以我选择使用gaussian_filter


我之前看过这个例子。但是,我无法在我的数组上使其工作。我应该注意到,我的数组是一个Python列表而不是numpy数组。这会导致问题吗?如果是这样,最简单的方法是将Python列表转换为numpy数组是什么? - dman87
嗯,实际上ndimage.gaussian_filter可以很好地处理列表的列表。例如,(ndimage.gaussian_filter(Z.tolist()))是有效的。问题必须在其他地方。没有看到数据很难说。不起作用是什么意思?是否会引发异常?还是结果看起来不对? - unutbu
你能否编辑你的问题,并提供一个简短的数据示例呢?它是一个字符串列表还是一个字符串嵌套列表?这些字符串是数字的字符串表示,例如"1.5",还是需要使用struct.unpack解包的二进制数据? - unutbu
是的,我尝试了从0.25到1000的范围,但是当我查看轮廓时得到了相同的结果。order kwarg 似乎也没有太大的区别。 - dman87
等等,我的代码出了点错误。(摸着头…)我觉得现在它能用了。但是它不能很好地平滑轮廓的锯齿状边缘。随着sigma值的增加,它最终只会减少从数据产生的轮廓级别。 - dman87
显示剩余2条评论

9
一种简单的平滑数据的方法是使用移动平均算法。其中一种简单的移动平均形式是在某个位置计算相邻测量值的平均值。例如,在一维测量序列a [1:N]中,可以通过a [n] =(a [n-1] + a [n] + a [n + 1])/ 3来计算a [n]的移动平均值。如果您遍历所有测量值,则完成了平滑处理。在这个简单的例子中,我们的平均窗口大小为3。您还可以使用不同大小的窗口,具体取决于您需要多少平滑处理。
为了使广泛应用程序的计算更简便快捷,您还可以使用基于卷积的算法。使用卷积的优点是您可以选择不同类型的平均值,例如加权平均值,只需更改窗口即可。
让我们进行一些编程示例。以下摘录需要安装Numpy、Matplotlib和Scipy。单击此处获取完整运行示例代码。
from __future__ import division
import numpy
import pylab
from scipy.signal import convolve2d

def moving_average_2d(data, window):
    """Moving average on two-dimensional data.
    """
    # Makes sure that the window function is normalized.
    window /= window.sum()
    # Makes sure data array is a numpy array or masked array.
    if type(data).__name__ not in ['ndarray', 'MaskedArray']:
        data = numpy.asarray(data)

    # The output array has the same dimensions as the input data 
    # (mode='same') and symmetrical boundary conditions are assumed
    # (boundary='symm').
    return convolve2d(data, window, mode='same', boundary='symm')

以下代码生成一些任意的噪声数据,然后使用四个不同大小的框窗口计算移动平均值。
M, N = 20, 2000  # The shape of the data array
m, n = 3, 10     # The shape of the window array

y, x = numpy.mgrid[1:M+1, 0:N]
# The signal and lots of noise
signal = -10 * numpy.cos(x / 500 + y / 10) / y
noise = numpy.random.normal(size=(M, N))
z = signal + noise

# Calculating a couple of smoothed data.
win = numpy.ones((m, n))
z1 = moving_average_2d(z, win)
win = numpy.ones((2*m, 2*n))
z2 = moving_average_2d(z, win)
win = numpy.ones((2*m, 4*n))
z3 = moving_average_2d(z, win)
win = numpy.ones((2*m, 10*n))
z4 = moving_average_2d(z, win)

接下来,为了查看不同的结果,这里是一些绘图的代码。

# Initializing the plot
pylab.close('all')
pylab.ion()
fig = pylab.figure()
bbox = dict(edgecolor='w', facecolor='w', alpha=0.9)
crange = numpy.arange(-15, 16, 1.) # color scale data range

# The plots
ax = pylab.subplot(2, 2, 1)
pylab.contourf(x, y, z, crange)
pylab.contour(x, y, z1, crange, colors='k')
ax.text(0.05, 0.95, 'n=10, m=3', ha='left', va='top', transform=ax.transAxes, 
    bbox=bbox)

bx = pylab.subplot(2, 2, 2, sharex=ax, sharey=ax)
pylab.contourf(x, y, z, crange)
pylab.contour(x, y, z2, crange, colors='k')
bx.text(0.05, 0.95, 'n=20, m=6', ha='left', va='top', transform=bx.transAxes, 
    bbox=bbox)

bx = pylab.subplot(2, 2, 3, sharex=ax, sharey=ax)
pylab.contourf(x, y, z, crange)
pylab.contour(x, y, z3, crange, colors='k')
bx.text(0.05, 0.95, 'n=40, m=6', ha='left', va='top', transform=bx.transAxes, 
    bbox=bbox)

bx = pylab.subplot(2, 2, 4, sharex=ax, sharey=ax)
pylab.contourf(x, y, z, crange)
pylab.contour(x, y, z4, crange, colors='k')
bx.text(0.05, 0.95, 'n=100, m=6', ha='left', va='top', transform=bx.transAxes, 
    bbox=bbox)

ax.set_xlim([x.min(), x.max()])
ax.set_ylim([y.min(), y.max()])

fig.savefig('movingavg_sample.png')
# That's all folks!

这里是不同大小窗口的绘制结果:Results 此处提供的示例代码在二维中使用简单的框形或矩形窗口。有几种不同类型的窗口可用,您可能需要查看维基百科了解更多示例。

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