Narysuj gładką linię za pomocą PyPlot

112

Mam następujący prosty skrypt, który wykreśla wykres:

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

Jak to jest teraz, linia biegnie prosto od punktu do punktu, co wygląda dobrze, ale moim zdaniem mogłoby być lepsze. Chcę wygładzić linię między punktami. W Gnuplot knułbym z smooth cplines.

Czy jest na to łatwy sposób w PyPlot? Znalazłem kilka samouczków, ale wszystkie wydają się dość złożone.

Paweł
źródło

Odpowiedzi:

167

Możesz użyć, scipy.interpolate.splineaby samodzielnie wygładzić swoje dane:

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 jest przestarzały w scipy 0.19.0, zamiast tego użyj klasy BSpline.

Przełączanie się z splinena BSplinenie jest prostym kopiowaniem / wklejaniem i wymaga drobnych poprawek:

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

Przed: zrzut ekranu 1

Po: zrzut ekranu 2

Olivier Verdier
źródło
2
Haha, to nie było trudne. Twoje zdrowie! :) Tylko uwaga dla innych, którzy mogliby szukać: musiałem zaimportować scipy, aby użyć linspace ().
Paul
Ups, przepraszam, powinienem był użyć np.linspace. Poprawione w mojej odpowiedzi.
Olivier Verdier
2
300 to liczba punktów do zrobienia między T.min () a T.max (). Użyłem 1000 i wygląda tak samo. Spróbuj jednak z 5, a zobaczysz różnicę.
CornSmith,
2
splinejest przestarzałe! spline jest przestarzały w scipy 0.19.0, zamiast tego użyj klasy BSpline:from scipy.interpolate import BSpline
user890739 Kwietnia
2
To nie zadziała, jeśli T nie jest posortowany. A także jeśli functiton (T) nie jest jeden do jednego.
Rahat Zaman
28

W tym przykładzie splajn działa dobrze, ale jeśli funkcja nie jest z natury gładka i chcesz mieć wygładzoną wersję, możesz również spróbować:

from scipy.ndimage.filters import gaussian_filter1d

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

jeśli zwiększysz sigma, możesz uzyskać bardziej wygładzoną funkcję.

Postępuj ostrożnie z tym. Modyfikuje oryginalne wartości i może nie być tym, czego chcesz.

Sajad Norouzi
źródło
10
Postępuj ostrożnie z tym. Modyfikuje oryginalne wartości i może nie być tym, czego chcesz.
tartaruga_casco_mole
8

Zakładam, że masz na myśli dopasowanie krzywej, a nie wygładzanie w kontekście twojego pytania. PyPlot nie ma żadnego wbudowanego wsparcia dla tego, ale możesz łatwo zaimplementować kilka podstawowych dopasowań krzywych samodzielnie, jak w kodzie widzianym tutaj , lub jeśli używasz GuiQwt, ma on moduł dopasowywania krzywych . (Prawdopodobnie możesz też ukraść kod z SciPy, aby to zrobić).

Nick Bastin
źródło
dzięki. Wypróbowałem dziesięć różnych równań i [Korzystanie z radialnych funkcji bazowych do wygładzania / interpolacji] [1] rbf = Rbf(x, y), fi = rbf(xi)było najlepszym z nich. [1]: scipy-cookbook.readthedocs.io/items/RadialBasisFunctions.html ,
Cloud Cho
1

Zobacz scipy.interpolatedokumentację, aby zobaczyć kilka przykładów.

Poniższy przykład demonstruje jego użycie dla liniowej i sześciennej interpolacji splajnu:

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

wprowadź opis obrazu tutaj

Mateen Ulhaq
źródło