你可以试试matplotlib.animation.ArtistAnimation。它的操作类似于FuncAnimation,因为您可以指定帧间隔、循环行为等,但所有绘图都是在动画步骤之前立即完成的。这是一个例子
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from matplotlib.animation import ArtistAnimation
n = 150
x = np.linspace(0, np.pi*4, n)
df = pd.DataFrame({'cos(x)' : np.cos(x),
'sin(x)' : np.sin(x),
'tan(x)' : np.tan(x),
'sin(cos(x))' : np.sin(np.cos(x))})
fig, axs = plt.subplots(nrows=2, ncols=2, figsize=(10,10))
lines = []
artists = [[]]
for ax, col in zip(axs.flatten(), df.columns.values):
lines.append(ax.plot(df[col])[0])
artists.append(lines.copy())
anim = ArtistAnimation(fig, artists, interval=500, repeat_delay=1000)
这里的缺点是每个艺术家要么被绘制,要么不被绘制,即你不能只绘制 Line2D 对象的一部分而不进行剪切。如果这与您的用例不兼容,那么您可以尝试使用 FuncAnimation 和 blit=True 并分块每次要绘制的数据以及使用 set_data() 而不是在每次迭代时清除和重绘。使用上述相同数据的示例:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from matplotlib.animation import FuncAnimation
n = 500
nf = 100
x = np.linspace(0, np.pi*4, n)
df = pd.DataFrame({'cos(x)' : np.cos(x),
'sin(x)' : np.sin(x),
'tan(x)' : np.tan(x),
'sin(cos(x))' : np.sin(np.cos(x))})
fig, axs = plt.subplots(2, 2, figsize=(5,5), dpi=50)
lines = []
for ax, col in zip(axs.flatten(), df.columns):
lines.append(ax.plot([], lw=0.5)[0])
ax.set_xlim(x[0] - x[-1]*0.05, x[-1]*1.05)
ax.set_ylim([min(df[col].values)*1.05, max(df[col].values)*1.05])
ax.tick_params(labelbottom=False, bottom=False, left=False, labelleft=False)
plt.subplots_adjust(hspace=0, wspace=0, left=0.02, right=0.98, bottom=0.02, top=0.98)
plt.margins(1, 1)
c = int(n / nf)
def animate(i):
if (i != nf - 1):
for line, col in zip(lines, df.columns):
line.set_data(x[:(i+1)*c], df[col].values[:(i+1)*c])
else:
for line, col in zip(lines, df.columns):
line.set_data(x, df[col].values)
return lines
anim = FuncAnimation(fig, animate, interval=2000/nf, frames=nf, blit=True)
编辑
针对cmets,这里是使用问题中更新代码的分块方案的实现:
x = benchmark_returns.index
y = benchmark_returns['Crypto 30']
y2 = benchmark_returns['Dow Jones 30']
y3 = benchmark_returns['NASDAQ']
y4 = benchmark_returns['S&P 500']
line, = ax.plot(x, y, color='k')
line2, = ax.plot(x, y2, color = 'b')
line3, = ax.plot(x, y3, color = 'r')
line4, = ax.plot(x, y4, color = 'g')
n = len(x) # Total number of rows
c = 50 # Chunk size
def update(num):
end = num * c if num * c < n else n - 1
line.set_data(x[:end], y[:end])
line2.set_data(x[:end], y2[:end])
line3.set_data(x[:end], y3[:end])
line4.set_data(x[:end], y4[:end])
return line, line2, line3, line4,
ani = animation.FuncAnimation(fig, update, interval = c, blit = True)
plt.show()
或者,更简洁
cols = benchmark_returns.columns.values
# or, for only a subset of the columns
# cols = ['Crypto 30', 'Dow Jones 30', 'NASDAQ', 'S&P 500']
colors = ['k', 'b', 'r', 'g']
lines = []
for c, col in zip(cols, colors):
lines.append(ax.plot(benchmark_returns.index, benchmark_returns[col].values, c=c)[0])
n = len(benchmark_returns.index)
c = 50 # Chunk size
def update(num):
end = num * c if num * c < n else n - 1
for line, col in zip(lines, cols):
line.set_data(benchmark_returns.index, benchmark_returns[col].values[:end])
return lines
anim = animation.FuncAnimation(fig, update, interval = c, blit=True)
plt.show()
如果您需要它在一段时间后停止更新,只需在FuncAnimation() 中设置frames 参数和repeat=False。