matplotlib 如何能再现动画滚动窗口随着时间的推移?

5uzkadbs  于 2023-10-24  发布在  其他
关注(0)|答案(1)|浏览(118)

我正在用1D时间序列数据进行实验,并试图通过GoogleColab notebook中我自己的数据的动画来重现以下方法。
它是关于再现STS transformation的动画(由series_to_supervised()函数实现,具有对过去时间n_in=9的回顾步骤)等于skforecast包中引入的Backtesting with refit and fixed training size (rolling origin)动画方法。它更多地是关于在实际时间序列数据y上选择traintest。可视化固定的列车大小并重新装配和预测下一步。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib.animation import FuncAnimation
from IPython.display import HTML
print(pd.__version__)

# Generate univariate (1D) time-series data into pandas DataFrame
import numpy as np
np.random.seed(123) # for reproducibility and get reproducible results

df = pd.DataFrame({
    "TS_24hrs": np.arange(0, 274),
    "count"   : np.abs(np.sin(2 * np.pi * np.arange(0, 274) / 7) + np.random.normal(0, 100.1, size=274)) # generate sesonality
})
#df = pd.read_csv('/content/U2996_24hrs_.csv', header=0, index_col=0).values
print(f"The raw data {df.shape}")
#print(f"The raw data columns {df.columns}")

# visulize data
import matplotlib.pyplot as plt
fig, ax = plt.subplots( figsize=(10,4))

# plot data
df['count'].plot(label=f'data or y', c='red' )
#df['count'].plot(label=f'data',  linestyle='--')
plt.xticks([0, 50, 100, 150, 200, 250, df['TS_24hrs'].iloc[-1]], visible=True, rotation="horizontal")

plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left")
plt.title('Plot of data')
plt.ylabel('count', fontsize=15)
plt.xlabel('Timestamp [24hrs]', fontsize=15)
plt.grid()
plt.show()

# slecet train/test data using series_to_supervised (STS)
from pandas import DataFrame, concat
def series_to_supervised( data, n_in, n_out=1, dropnan=True):
    """
    Frame a time series as a supervised learning dataset.
    Arguments:
        data: Sequence of observations as a list or NumPy array.
        n_in: Number of lag observations as input (X).
        n_out: Number of observations as output (y).
        dropnan: Boolean whether or not to drop rows with NaN values.
    Returns:
        Pandas DataFrame of series framed for supervised learning.
    """
    n_vars = 1 if type(data) is list else data.shape[1]
    df = pd.DataFrame(data)
    cols = list()
    # input sequence (t-n, ... t-1)
    for i in range(n_in, 0, -1):
        cols.append(df.shift(i))
    # forecast sequence (t, t+1, ... t+n)
    for i in range(0, n_out):
        cols.append(df.shift(-i))
    # put it all together
    agg = concat(cols, axis=1)
    # drop rows with NaN values
    if dropnan:
        agg.dropna(inplace=True)
    return agg.values

values=series_to_supervised(df, n_in=9)
data_x,data_y =values[:, :-1], values[:, -1]

print(data_x.shape)
print(data_y.shape)

# define animation function
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(40, 8))
plt.subplots_adjust(bottom=0.25)
plt.xticks(fontsize=12)
ax.set_xticks(range(0, len(data_y), 9))
ax.set_yticks(range(0, 2500, 200))

data_y = pd.Series(data_y)
data_y.plot(color='r', linestyle='-', label="y")
ax.set_title('Time Series')
ax.set_xlabel('Time')
ax.set_ylabel('Value')
ax.legend(loc="upper left")
ax.grid(True, which='both', linestyle='-', linewidth=3)
ax.set_facecolor('gainsboro')

ax.spines['bottom'].set_position('zero')
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')

nested_list = list(trainX_tss)
lines = [ax.plot([], [], color='g', linestyle='-')[0] for _ in range(len(trainX_tss))]

def init():
    for line in lines:
        line.set_data([], [])
    return lines

def update(frame):
    for i, line in enumerate(lines):
        data = pd.Series(nested_list[i], index=range(frame + i, frame + i + 9))
        line.set_data([], [])
        line.set_data(data.index, data)
    return lines

# define animation setup
anim = FuncAnimation(fig, update,
                    frames=len(nested_list) - 9,
                    init_func=init,
                    interval=500,
                    blit=True,
                    repeat=False)

# Save animation (.gif))
anim.save('BrowniamMotion.gif', writer = "pillow", fps=10 )

# visulize animation in GoogleColab Notebook
# suppress final output
plt.close(0)
HTML(anim.to_html5_video())

STS transformation

  • 多步或序列预测**另一种类型的预测问题是使用过去的观测值来预测未来观测值的序列。这可能称为序列预测或多步预测。*

到目前为止,我可以达到这个输出,这是如此丑陋和不正确。

mf98qq94

mf98qq941#

在你想要的动画中,只有绿色和蓝色矩形移动,数据是恒定的。所以你的update()函数应该反映它。
所以你需要的是按照你想要的方式设置初始图,创建你想要动画的部分(使用init()),然后使用update()创建帧:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.patches import Rectangle
import pandas as pd
from IPython.display import HTML

# create data
df = pd.DataFrame({
    "TS_24hrs": np.arange(0, 274),
    "count"   : np.abs(np.sin(2 * np.pi * np.arange(0, 274) / 7) + np.random.normal(0, 100.1, size=274)) # generate sesonality
})

# create plot
plt.style.use("ggplot")  # <-- set overall look
fig, ax = plt.subplots( figsize=(10,4))

# plot data
plt.plot(df['TS_24hrs'], df['count'], 'r-', linewidth=0.5,  label='data or y')

# make graph beautiful
plt.plot([], [], 'g-', label="Train", linewidth=8, alpha=0.3) # <-- dummy legend entry
plt.plot([], [], 'b-', label="Test", linewidth=8, alpha=0.3)  # <-- dummy legend entry 
plt.xticks([0, 50, 100, 150, 200, 250, df['TS_24hrs'].iloc[-1]], visible=True, rotation="horizontal")

plt.title('Plot of data')
plt.ylabel('count', fontsize=15)
plt.xlabel('Timestamp [24hrs]', fontsize=15)
plt.grid(True)
plt.legend(loc="upper left")  
fig.tight_layout(pad=1.2)

Y_LIM = 280
TRAIN_WIDTH = 25
TEST_WIDTH = 10

def init():
    rects = [Rectangle((0, 0), TRAIN_WIDTH, Y_LIM, alpha=0.3, facecolor='green'),
             Rectangle((0 + TRAIN_WIDTH, 0), TEST_WIDTH, Y_LIM, alpha=0.3, facecolor='blue')]
    patches = []
    for rect in rects:
            patches.append(ax.add_patch(rect))
    return patches

def update(x_start):
    patches[0].xy = (x_start, 0)
    patches[1].xy = (x_start + TRAIN_WIDTH, 0)    
    return patches

# create "Train" and "Test" areas
patches = init()

ani = FuncAnimation(
    fig,
    update, 
    frames=np.linspace(0, 230, 40),  # all starting points
    interval=500,
    blit=True)

HTML(ani.to_html5_video())

相关问题