如何在Matplotlib动画中添加文本(支持外部显示)
Matplotlib动画添加文本的问题解决
问题根源
ax.cla()的副作用:每次帧更新时调用ax.cla()会清空轴上所有元素,包括初始化时创建的文本对象,导致后续无法修改显示内容。- 返回值格式错误:尝试返回
(self.lines, self.text)时,self.lines是线条组成的元组,整体返回的是嵌套元组,而Matplotlib的blitting机制需要扁平的Artist对象列表/元组,因此触发AttributeError。
解决方案
关键修改点
- 将文本创建在Figure层级:用
fig.text()替代ax.text(),避免被ax.cla()清除,同时方便放在绘图区域外部。 - 调整返回值为扁平结构:把所有需要更新的Artist(线条+文本)合并成一个扁平元组返回。
- 修正辅助函数逻辑:修复
get_n函数的循环取数错误。
修改后的完整代码
import math import sys import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation, FFMpegWriter line_x = [0,1,2,3,4,5,6,7,8,9,10,11,12] line1_y = [3,5,7,9,11,19,23,26,29,31,37,40,45] line2_y = [0,2,5,7,10,10,8,5,3,2,1,3,5] line3_y = [39,38,32,29,26,22,19,13,10,8,7,6,3] set_lines = [line1_y, line2_y, line3_y] n_lineas = [1,2,3,1,3,2,3,1,3,2,1,2] show = True thecolors = ['blue','red','violet'] thelegends = ['unus','duo','tres'] if len(sys.argv)==2 and sys.argv[1]=='movie': show = False def get_n(thelist,c): while c >= len(thelist): c -= len(thelist) # 修正原代码的赋值错误 return thelist[c] class Update: def __init__(self, ax, limit_x, fig): self.ax = ax self.fig = fig self.lx = limit_x if limit_x != 0: self.ax.set_xlim(0, limit_x) self.ax.set_ylim(0, 45) self.ax.set_aspect('equal') self.ax.grid(True) self.ax.set_xlabel("Y (meters)") self.ax.set_ylabel("X (meters)") self.lines = () self.counter = 0 # 在Figure层级创建文本,放在绘图区域上方外部(归一化坐标) self.text = self.fig.text(0.5, 1.02, '', ha='center', fontsize=12) def __call__(self, frame): print("Frame: ", frame) lines = [] # 清空轴内容,不影响Figure层级的文本 self.ax.cla() self.ax.set_xlim(0, self.lx) self.ax.set_ylim(0, 45) self.ax.grid(True) self.ax.set_xlabel("Y (meters)") self.ax.set_ylabel("X (meters)") n_lines_this_time = get_n(n_lineas, self.counter) self.counter += 1 print(n_lines_this_time,"lines this time") for myline in range(n_lines_this_time): line, = self.ax.plot([],[],'.-', color=thecolors[myline], label=thelegends[myline]) line.set_xdata(line_x) line.set_ydata(set_lines[myline]) lines.append(line) self.ax.legend() self.lines = tuple(lines) # 更新文本内容 self.text.set_text(f"Frame {frame}") # 返回扁平的Artist对象元组:所有线条 + 文本 return (*self.lines, self.text) def init(self): print("Init") line, = self.ax.plot([],[]) self.text.set_text('') return line, self.text fig, ax = plt.subplots(1, 1, figsize=(10,10)) plt.gcf().canvas.mpl_connect( 'key_release_event', lambda event: sys.exit(0) if event.key == 'escape' else None) ug_i = Update(ax, 13, fig) anim = FuncAnimation(fig, ug_i, init_func=ug_i.init, frames=10, interval=1000, blit=True, repeat=False) if not show: writervideo = FFMpegWriter(fps=1) anim.save('whatever.mp4', writer=writervideo) print('done') plt.close() else: plt.show()
额外说明
- 文本使用Figure归一化坐标
(0.5, 1.02),实现水平居中、轴上方外部的显示效果,ha='center'确保文本对齐。 - 用
ax.legend()替代全局的plt.legend(),避免状态干扰。
内容的提问来源于stack exchange,提问作者KansaiRobot
相关产品推荐
相关产品推荐

