Trace uma linha suave com PyPlot

112

Eu tenho o seguinte script simples que traça um gráfico:

import matplotlib.pyplot as plt
import numpy as np

T = np.array([6, 7, 8, 9, 10, 11, 12])
power = np.array([1.53E+03, 5.92E+02, 2.04E+02, 7.24E+01, 2.72E+01, 1.10E+01, 4.70E+00])

plt.plot(T,power)
plt.show()

Do jeito que está agora, a linha vai direto de um ponto a outro, o que parece bom, mas poderia ser melhor na minha opinião. O que eu quero é suavizar a linha entre os pontos. No Gnuplot, eu teria planejado smooth cplines.

Existe uma maneira fácil de fazer isso no PyPlot? Encontrei alguns tutoriais, mas todos parecem bastante complexos.

Paulo
fonte

Respostas:

167

Você pode usar scipy.interpolate.splinepara suavizar seus dados sozinho:

from scipy.interpolate import spline

# 300 represents number of points to make between T.min and T.max
xnew = np.linspace(T.min(), T.max(), 300)  

power_smooth = spline(T, power, xnew)

plt.plot(xnew,power_smooth)
plt.show()

spline está obsoleto no scipy 0.19.0; em vez disso, use a classe BSpline.

Mudar de splinepara BSplinenão é uma tarefa simples de copiar / colar e requer alguns ajustes:

from scipy.interpolate import make_interp_spline, BSpline

# 300 represents number of points to make between T.min and T.max
xnew = np.linspace(T.min(), T.max(), 300) 

spl = make_interp_spline(T, power, k=3)  # type: BSpline
power_smooth = spl(xnew)

plt.plot(xnew, power_smooth)
plt.show()

Antes: captura de tela 1

Depois de: captura de tela 2

Olivier Verdier
fonte
2
Haha, isso não foi difícil. Felicidades! :) Apenas uma nota para outros que possam estar procurando: Tive que importar o scipy para usar o linspace ().
Paul,
Opa, desculpe, deveria ter usado np.linspace. Corrigido em minha resposta.
Olivier Verdier
2
O 300 é quantos pontos fazer entre T.min () e T.max (). Usei 1000 e parece o mesmo. Experimente com 5 e você verá a diferença.
CornSmith de
2
splineestá obsoleto! spline está obsoleto no scipy 0.19.0, use a classe BSpline em vez disso:from scipy.interpolate import BSpline
user890739
2
Isso não funcionará se o T não estiver classificado. E também se a função (T) não for um-para-um.
Rahat Zaman
28

Para este exemplo, o spline funciona bem, mas se a função não é inerentemente suave e você deseja ter uma versão suavizada, você também pode tentar:

from scipy.ndimage.filters import gaussian_filter1d

ysmoothed = gaussian_filter1d(y, sigma=2)
plt.plot(x, ysmoothed)
plt.show()

se você aumentar o sigma, poderá obter uma função mais suavizada.

Prossiga com cuidado com este. Ele modifica os valores originais e pode não ser o que você deseja.

Sajad Norouzi
fonte
10
Prossiga com cuidado com este. Ele modifica os valores originais e pode não ser o que você deseja.
tartaruga_casco_mole
8

Presumo que você queira dizer ajuste de curva e não anti-aliasing do contexto de sua pergunta. PyPlot não tem nenhum suporte embutido para isso, mas você pode facilmente implementar alguns ajustes básicos de curva por conta própria, como o código visto aqui , ou se você estiver usando GuiQwt, ele tem um módulo de ajuste de curva . (Você provavelmente também pode roubar o código do SciPy para fazer isso).

Nick Bastin
fonte
obrigado. Tentei dez equações diferentes e [Usando funções de base radial para suavização / interpolação] [1] rbf = Rbf(x, y), fi = rbf(xi)foi a melhor entre elas. [1]: scipy-cookbook.readthedocs.io/items/RadialBasisFunctions.html ,
Cloud Cho
1

Veja a scipy.interpolatedocumentação para alguns exemplos.

O exemplo a seguir demonstra seu uso, para interpolação linear e cúbica de spline:

>>> from scipy.interpolate import interp1d

>>> x = np.linspace(0, 10, num=11, endpoint=True)
>>> y = np.cos(-x**2/9.0)
>>> f = interp1d(x, y)
>>> f2 = interp1d(x, y, kind='cubic')

>>> xnew = np.linspace(0, 10, num=41, endpoint=True)
>>> import matplotlib.pyplot as plt
>>> plt.plot(x, y, 'o', xnew, f(xnew), '-', xnew, f2(xnew), '--')
>>> plt.legend(['data', 'linear', 'cubic'], loc='best')
>>> plt.show()

insira a descrição da imagem aqui

Mateen Ulhaq
fonte