使用matplotlib的animation.ArtistAnimation()生成视频出现全空白问题
问题原因与修正方案
核心错误点
- Artist 所属画布不匹配:你在循环内为每帧创建了独立的
fig对象,所有绘制的曲线、散点、外部图片元素都绑定在这些临时画布上,最后生成动画时新建的fig_ani是完全空白的新画布,没有绑定任何绘制元素,因此输出视频全白。 - 帧元素收集不全:当前
ims列表仅添加了外部原子图的im对象,上半部分的NEB曲线、散点等元素未加入帧元素列表,即使画布匹配也无法显示完整的帧内容。 - 循环内重复创建画布会导致内存占用过高,也容易引发元素归属混乱。
- 原代码中
axin1.set_xlim(0, 0.3, 0.1)的参数写法错误,set_xlim仅支持传入左右边界,步长参数会触发参数非法,需要删除多余的步长参数,步长设置需要用set_xticks实现。
修正后代码
import numpy as np from matplotlib import pyplot as plt from matplotlib import image as mpimg from matplotlib import animation plotfile = r'C:\Users\handa\Desktop\result.txt' RD = np.loadtxt(plotfile)[:, 0] PE = np.loadtxt(plotfile)[:, 1] - np.loadtxt(plotfile)[0, 1] ims = [] # 仅在循环外创建一次画布和所有子图,提前配置固定属性 fig = plt.figure(figsize = (8, 12)) ax1 = fig.add_subplot(211) ax1.set_xlabel('Reaction Coordinate', fontsize = 16) ax1.set_ylabel('Energy (eV)', fontsize = 16) ax1.minorticks_on() ax1.tick_params(which = 'both', axis = 'both', direction = 'in', labelsize = 14) axin1 = ax1.inset_axes([0.1, 0.45, 0.5, 0.5]) axin1.set_xlabel('Reaction Coordinate', fontsize = 12) axin1.set_ylabel('Energy (eV)', fontsize = 12) axin1.tick_params(which = 'both', axis = 'both', direction = 'in', labelsize = 10) axin1.set_xlim(0, 0.3) axin1.set_ylim(-0.1, 1) # 若要设置x轴步长可使用下方代码 # axin1.set_xticks(np.arange(0, 0.31, 0.1)) ax2 = fig.add_subplot(212) ax2.axis(False) for _ in range(0, 3): mark = [_] RD1 = RD[mark] RD2 = np.delete(RD, mark) PE1 = PE[mark] PE2 = np.delete(PE, mark) # 绘制当前帧所有元素 line, = ax1.plot(RD, PE, 'b-', label = r'NEB Energy Curve', linewidth = 3) scatter1, = ax1.plot(RD1, PE1, 'bo', label = r'NEB Energy Curve', markersize = 10, markerfacecolor = 'red') scatter2, = ax1.plot(RD2, PE2, 'bo', label = r'NEB Energy Curve', markersize = 10, markerfacecolor = 'white') linein, = axin1.plot(RD, PE, 'b-', label = r'NEB Energy Curve', linewidth = 3) scatterin1, = axin1.plot(RD1, PE1, 'bo', label = r'NEB Energy Curve', markersize = 10, markerfacecolor = 'red') scatterin2, = axin1.plot(RD2, PE2, 'bo', label = r'NEB Energy Curve', markersize = 10, markerfacecolor = 'white') num = str(_).zfill(4) atoms = mpimg.imread(f'C:\\Users\\handa\\Desktop\\atomfig\\atomfig{num}.png') im = ax2.imshow(atoms, animated = True) # 收集当前帧所有元素到列表 ims.append([line, scatter1, scatter2, linein, scatterin1, scatterin2, im]) # 直接用全局画布生成动画 ani = animation.ArtistAnimation(fig, ims, interval = 500, repeat = False) # 如果需要导出为视频文件,取消注释下方代码,需提前安装配置ffmpeg # ani.save('output.mp4', writer='ffmpeg', dpi=100) plt.show()
额外说明
- 提前在循环外定义了画布和所有子图的固定属性,仅在循环内更新随帧变化的绘制元素,大幅降低内存占用
- 每帧的所有绘制元素都被完整收集到
ims列表中,保证动画显示完整内容 - 直接使用绘制元素所属的全局画布生成动画,避免画布不匹配导致的空白问题
内容的提问来源于stack exchange,提问作者friedchicken
相关产品推荐
相关产品推荐

