我想使用FuncAnimation
在matplotlib
中创建动画。动画包含各种“阶段”,我想通过向两个相应帧之间的间隔添加额外的延迟来分离(强调)这些阶段。考虑下面的示例代码,该代码绘制了五个圆,并且每两个连续圆的绘制应间隔1秒:
import time
from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import numpy as np
f, ax = plt.subplots()
ax.set_xlim([-5, 5])
ax.set_ylim([-5, 5])
radius = 1
dp = 2*np.pi / 50
circles = [[(radius, 0)]]
plots = ax.plot([radius], [0])
def update(frame):
global radius
if frame % 50 == 0:
radius += 1
circles.append([(radius, 0)])
plots.extend(ax.plot([radius], [0]))
# I want to add a delay here, i.e. before the drawing of a new circle starts.
# This works for `plt.show()` however it doesn't when saving the animation.
time.sleep(1)
angle = (frame % 50) * dp
circles[-1].append((radius * np.cos(angle), radius * np.sin(angle)))
plots[-1].set_data(*zip(*circles[-1]))
return plots[-1]
animation = FuncAnimation(f, update, frames=range(1, 251), interval=50, repeat=False)
### Uncomment one of the following options.
# animation.save('test.mp4', fps=20)
# with open('test.html', 'w') as fh:
# fh.write(animation.to_html5_video())
# plt.show()
此功能在通过plt.show()
播放动画时有效,但是在另存为.mp4
或HTML5视频时无效。这是有道理的,因为根据文档,FPS确定mp4视频的帧延迟,并且interval
参数用于HTML5视频。然后,只是一帧接一帧地播放(也忽略了任何计算时间)。
那么我该如何添加保存动画时保留的延迟?
答案 0 :(得分:0)
您应该能够为frames
参数使用生成函数。例如:
from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import numpy as np
INTERVAL = 50 # ms
HOLD_MS = 1000
HOLD_COUNT = HOLD_MS // INTERVAL
def frame_generator():
for frame in range(1, 251):
# Yield the frame first
yield frame
# If we should "sleep" here, yield None HOLD_COUNT times
if frame % 50 == 0:
for _ in range(HOLD_COUNT):
yield None
f, ax = plt.subplots()
ax.set_xlim([-5, 5])
ax.set_ylim([-5, 5])
radius = 1
dp = 2*np.pi / 50
circles = [[(radius, 0)]]
plots = ax.plot([radius], [0])
def update(frame):
global radius
if frame is None: return #--------------------------------- Added
if frame % 50 == 0:
radius += 1
circles.append([(radius, 0)])
plots.extend(ax.plot([radius], [0]))
#-------------------------------------------------------- sleep removed
angle = (frame % 50) * dp
circles[-1].append((radius * np.cos(angle), radius * np.sin(angle)))
plots[-1].set_data(*zip(*circles[-1]))
return plots[-1]
# Slightly changed
animation = FuncAnimation(f, update, frames=frame_generator(), interval=INTERVAL, repeat=False)
plt.show()
应该工作。
print(list(frame_generator()))
可能有助于弄清正在发生的事情。
答案 1 :(得分:0)
您可以使用frame
参数来引导动画。本质上,在帧n
之后的暂停与重复显示帧编号n
直到暂停结束相同。例如。如果您以每秒1帧的速度运行动画,并且在第二帧之后要暂停3秒,则可以提供
0, 1, 1, 1, 1, 2, 3, ....
作为框架,因此编号为1的框架显示了四次。
可以在您的代码中按以下步骤应用该概念。
from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import numpy as np
f, ax = plt.subplots()
ax.set_xlim([-5, 5])
ax.set_ylim([-5, 5])
radius = 0
bu = 50
dp = 2*np.pi / bu
circles = [[(radius, 0)]]
plots = ax.plot([radius], [0])
def update(frame):
global radius
if frame % bu == 0:
radius += 1
circles.append([(radius, 0)])
plots.extend(ax.plot([radius], [0]))
angle = (frame % bu) * dp
circles[-1].append((radius * np.cos(angle), radius * np.sin(angle)))
plots[-1].set_data(*zip(*circles[-1]))
return plots[-1]
interval = 50 # milliseconds
pause = int(1 * 1000 / interval)
cycles = 4
frames = []
for c in range(cycles):
frames.extend([np.arange(c*bu, (c+1)*bu), np.ones(pause)*((c+1)*bu)])
frames = np.concatenate(frames)
animation = FuncAnimation(f, update, frames=frames, interval=50, repeat=False)
### Uncomment one of the following options.
# animation.save('test.mp4', fps=20)
# with open('test.html', 'w') as fh:
# fh.write(animation.to_html5_video())
plt.show()