Python Matplotlib - 平滑绘制带有日期值的x轴的曲线

5

我正在尝试使一个图形曲线更加平滑,但由于x轴的值是日期,因此我很难做到这一点。我们假设有以下数据框:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
%matplotlib inline

startDate = '2015-05-15'
endDate = '2015-12-5'
index = pd.date_range(startDate, endDate)
data = np.random.normal(0, 1, size=len(index))
cols = ['value']

df = pd.DataFrame(data, index=index, columns=cols)

然后我们绘制数据。
fig, axs = plt.subplots(1,1, figsize=(18,5))
x = df.index
y = df.value
axs.plot(x, y)
fig.show()

我们得到:

enter image description here

现在要平滑这条线,已经有了一些有用的stackoverflow问题,例如:

但我似乎无法让某些代码针对我的示例工作,有什么建议吗?

3个回答

8
您可以使用与pandas一起提供的插值功能。由于您的数据框已经有每个索引的值,因此可以使用更稀疏的索引填充它,并使用NaN值填充以前不存在的所有索引。然后,在选择可用方法之一进行插值并绘制数据之后:
index_hourly = pd.date_range(startDate, endDate, freq='1H')
df_smooth = df.reindex(index=index_hourly).interpolate('cubic')
df_smooth = df_smooth.rename(columns={'value':'smooth'})

df_smooth.plot(ax=axs, alpha=0.7)
df.plot(ax=axs, alpha=0.7)
fig.show()

enter image description here


1
有一个解决方法,我们将创建两个图形 - 1)非平滑/未插值,带有日期标签2)平滑,没有日期标签。
使用参数linestyle=" "绘制1),并将要绘制的日期转换为字符串类型。
使用参数linestyle="-"绘制2),并分别使用np.linespacemake_interp_spline对x轴和y轴进行插值。
以下是讨论的解决方法在您的代码中的用法。
# your initial code
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from scipy.interpolate import make_interp_spline
%matplotlib inline
startDate = "2015-05-15"
endDate = "2015-07-5" #reduced the end date so smoothness is clearly seen
index = pd.date_range(startDate, endDate)
data = np.random.normal(0, 1, size=len(index))
cols = ["value"]

df = pd.DataFrame(data, index=index, columns=cols)
fig, axs = plt.subplots(1, 1, figsize=(40, 12))
x = df.index
y = df.value

# workaround by creating linespace for length of your x axis
x_new = np.linspace(0, len(df.index), 300)
a_BSpline = make_interp_spline(
    [i for i in range(0, len(df.index))],
    df.value,
    k=5,
)
y_new = a_BSpline(x_new)

# plot this new plot with linestyle = "-"
axs.plot(
    x_new[:-5], # removing last 5 entries to remove noise, because interpolation outputs large values at the end.
    y_new[:-5],
    "-",
    label="interpolated"
)

# to get the date on x axis we will keep our previous plot but linestyle will be None so it won't be visible
x = list(x.astype(str))
axs.plot(x, y, linestyle=" ", alpha=0.75, label="initial")
xt = [x[i] for i in range(0,len(x),5)]
plt.xticks(xt,rotation="vertical")
plt.legend()
fig.show()

结果图

plot

重叠图以查看平滑度。

plot

0

根据你所说的“平滑”具体指什么,最简单的方法可能是使用savgol_filter或类似的工具。与插值样条不同,这种方法意味着平滑线不会通过测量点,从而有效地过滤掉高频噪声。

from scipy.signal import savgol_filter

...
windowSize = 21
polyOrder = 1
smoothed = savgol_filter(values, windowSize, polyOrder)
axes.plot(datetimes, smoothed, color=chart.color)

多项式阶数越高,平滑线就越接近原始数据。

以下是一个例子。 原始数据和平滑数据的比较图表。


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