使用PyPlot绘制平滑线

时间:2011-03-12 16:06:39

标签: python plot matplotlib curvesmoothing

我有以下简单的脚本绘制图表:

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

就像现在一样,这条直线从一点到另一点直线看起来不错,但在我看来可能更好。我想要的是平滑点之间的界限。在Gnuplot中,我会用smooth cplines绘制。

在PyPlot中有一种简单的方法吗?我找到了一些教程,但它们看起来都相当复杂。

8 个答案:

答案 0 :(得分:136)

您可以使用scipy.interpolate.spline自行平滑数据:

from scipy.interpolate import spline

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

power_smooth = spline(T,power,xnew)

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

  

spline在scipy 0.19.0中已弃用,改为使用Bspline类。

spline切换到Bspline不是简单的复制/粘贴,需要稍微调整一下:

from scipy.interpolate import make_interp_spline, BSpline

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

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

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

在: screenshot 1

在: screenshot 2

答案 1 :(得分:9)

在此示例中,样条曲线效果很好,但是如果函数固有地不平滑,并且您想要平滑的版本,也可以尝试:

from scipy.ndimage.filters import gaussian_filter1d

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

如果增加sigma,则可以获得更平滑的功能。

请谨慎进行此操作。它会修改原始值,可能不是您想要的。

答案 2 :(得分:6)

我认为你的意思是curve-fitting而不是anti-aliasing。 PyPlot没有任何内置的支持,但你可以自己轻松地实现一些基本的曲线拟合,比如看到here的代码,或者如果你使用GuiQwt它有一个曲线拟合{{3 }}。 (您也可以从module窃取代码来执行此操作。)

答案 3 :(得分:3)

有关某些示例,请参见scipy.interpolate文档。

以下示例演示了其在线性和三次样条插值中的用法:

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

enter image description here

答案 4 :(得分:1)

这是一种简单的日期解决方案:

from scipy.interpolate import make_interp_spline
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as dates
from datetime import datetime

data = {
    datetime(2016, 9, 26, 0, 0): 26060, datetime(2016, 9, 27, 0, 0): 23243,
    datetime(2016, 9, 28, 0, 0): 22534, datetime(2016, 9, 29, 0, 0): 22841,
    datetime(2016, 9, 30, 0, 0): 22441, datetime(2016, 10, 1, 0, 0): 23248 
}
#create data
date_np = np.array(list(data.keys()))
value_np = np.array(list(data.values()))
date_num = dates.date2num(date_np)
# smooth
date_num_smooth = np.linspace(date_num.min(), date_num.max(), 100) 
spl = make_interp_spline(date_num, value_np, k=3)
value_np_smooth = spl(date_num_smooth)
# print
plt.plot(date_np, value_np)
plt.plot(dates.num2date(date_num_smooth), value_np_smooth)
plt.show()

example

答案 5 :(得分:1)

另一种方法,根据您使用的参数稍微修改函数:

from statsmodels.nonparametric.smoothers_lowess import lowess

def smoothing(x, y):
    lowess_frac = 0.15  # size of data (%) for estimation =~ smoothing window
    lowess_it = 0
    x_smooth = x
    y_smooth = lowess(y, x, is_sorted=False, frac=lowess_frac, it=lowess_it, return_sorted=False)
    return x_smooth, y_smooth

对于我的特定应用案例,这比其他答案更适合。

答案 6 :(得分:0)

值得您花时间查看用于绘制平滑线的 seaborn

seaborn lmplot 函数将绘制数据和回归模型拟合。

以下说明多项式和 lowess 拟合:

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

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

df = pd.DataFrame(data = {'T': T, 'power': power})
    
sns.lmplot(x='T', y='power', data=df, ci=None, order=4, truncate=False)
sns.lmplot(x='T', y='power', data=df, ci=None, lowess=True, truncate=False)

enter image description here

order = 4 多项式拟合过拟合这个玩具数据集。我没有在这里展示它,但 order = 2order = 3 给出了更糟糕的结果。

enter image description here

lowess = True 拟合对这个小数据集欠拟合,但可能会在更大的数据集上提供更好的结果。

查看 seaborn regression tutorial 以获取更多示例。

答案 7 :(得分:0)

我发现最简单的 implementations 之一是使用 Tensorboard 使用的指数移动平均线:

def smooth(scalars: List[float], weight: float) -> List[float]:  # Weight between 0 and 1
    last = scalars[0]  # First value in the plot (first timestep)
    smoothed = list()
    for point in scalars:
        smoothed_val = last * weight + (1 - weight) * point  # Calculate smoothed value
        smoothed.append(smoothed_val)                        # Save it
        last = smoothed_val                                  # Anchor the last smoothed value
        
    return smoothed


ax.plot(x_labels, smooth(train_data, .9), x_labels, train_data)

enter image description here