继承FuncAnimation的动画播放器末尾重放索引越界问题如何解决
问题根源
原代码在动画播放到首尾边界时仅停止了播放进程,没有重置当前帧索引self.i的状态,再次点击播放按钮时,索引会超出设定的min/max范围,调用更新函数时就会触发数组索引越界错误。
优化方案(推荐:播放结束后点击自动从头重播)
仅需修改forward、backward两个方法,同时补全原示例缺失的numpy导入即可,完整可运行代码如下:
import numpy as np import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation import mpl_toolkits.axes_grid1 import matplotlib.widgets class Player(FuncAnimation): def __init__(self, fig, func, frames=None, init_func=None, fargs=None, save_count=None, mini=0, maxi=100, pos=(0.125, 0.92), **kwargs): self.i = 0 self.min=mini self.max=maxi self.runs = True self.forwards = True self.fig = fig self.func = func self.setup(pos) FuncAnimation.__init__(self,self.fig, self.func, frames=self.play(), init_func=init_func, fargs=fargs, save_count=save_count, **kwargs ) def play(self): while self.runs: self.i = self.i+self.forwards-(not self.forwards) if self.i > self.min and self.i < self.max: yield self.i else: self.stop() yield self.i def start(self): self.runs=True self.event_source.start() def stop(self, event=None): self.runs = False self.event_source.stop() def forward(self, event=None): self.forwards = True # 新增:如果已经到最大帧,重置到开头 if self.i >= self.max: self.i = self.min self.start() def backward(self, event=None): self.forwards = False # 新增:如果已经到最小帧,重置到末尾 if self.i <= self.min: self.i = self.max self.start() def oneforward(self, event=None): self.forwards = True self.onestep() def onebackward(self, event=None): self.forwards = False self.onestep() def onestep(self): if self.i > self.min and self.i < self.max: self.i = self.i+self.forwards-(not self.forwards) elif self.i == self.min and self.forwards: self.i+=1 elif self.i == self.max and not self.forwards: self.i-=1 self.func(self.i) self.fig.canvas.draw_idle() def setup(self, pos): playerax = self.fig.add_axes([pos[0],pos[1], 0.22, 0.04]) divider = mpl_toolkits.axes_grid1.make_axes_locatable(playerax) bax = divider.append_axes("right", size="80%", pad=0.05) sax = divider.append_axes("right", size="80%", pad=0.05) fax = divider.append_axes("right", size="80%", pad=0.05) ofax = divider.append_axes("right", size="100%", pad=0.05) self.button_oneback = matplotlib.widgets.Button(playerax, label=u'$⧏$') self.button_back = matplotlib.widgets.Button(bax, label=u'$◀$') self.button_stop = matplotlib.widgets.Button(sax, label=u'$■$') self.button_forward = matplotlib.widgets.Button(fax, label=u'$▶$') self.button_oneforward = matplotlib.widgets.Button(ofax, label=u'$⧐$') self.button_oneback.on_clicked(self.onebackward) self.button_back.on_clicked(self.backward) self.button_stop.on_clicked(self.stop) self.button_forward.on_clicked(self.forward) self.button_oneforward.on_clicked(self.oneforward) ### 使用方式和FuncAnimation完全一致 fig, ax = plt.subplots() x = np.linspace(0,6*np.pi, num=100) y = np.sin(x) ax.plot(x,y) point, = ax.plot([],[], marker="o", color="crimson", ms=15) def update(i): point.set_data(x[i],y[i]) ani = Player(fig, update, maxi=len(y)-1) plt.show()
可选方案(播放结束后点击播放无响应)
如果不需要重播效果,只需要避免报错,将上面forward和backward方法的逻辑替换为边界判断即可:
def forward(self, event=None): self.forwards = True # 只有还没到最大帧才启动播放 if self.i < self.max: self.start() def backward(self, event=None): self.forwards = False # 只有还没到最小帧才启动播放 if self.i > self.min: self.start()
内容的提问来源于stack exchange,提问作者fishbacp
相关产品推荐
相关产品推荐

