Сглаживание данных в контурной диаграмме с помощью Matplotlib - PullRequest
3 голосов
/ 08 ноября 2011

Я работаю над созданием контурного графика с использованием 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 файл. Я могу посмотреть на значения после того, как я использую Gaussian_filter, и они делают менять. Но изменения не настолько велики, чтобы повлиять на контурный график.

Ответы [ 2 ]

11 голосов
/ 08 ноября 2011

Вы можете сгладить данные с помощью 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.

8 голосов
/ 14 ноября 2011

Один простой способ сгладить данные - использовать алгоритм скользящее среднее . Одной простой формой скользящего среднего является вычисление среднего значения соседних измерений в определенной позиции. Например, в одномерной серии измерений a [1: N] скользящее среднее при a [n] можно рассчитать как a [n] = (a [n-1] + a [n] + a [ n + 1]) / 3, например. Если вы пройдете все свои измерения, все готово. В этом простом примере наше окно усреднения имеет размер 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

В приведенном здесь примере кода используется простое окно (или прямоугольное окно) в двух измерениях. Доступно несколько различных типов окон, и вы можете проверить Wikipedia для большего количества примеров.

...