如何用tikzplotlib将Matplotlib FuncAnimation动画转为含完整模拟的TeX文件?
用tikzplotlib结合LaTeX animate包实现动态模拟导出
tikzplotlib本身不直接支持导出动画,但可以通过生成时间序列的TikZ代码片段,再结合LaTeX的animate包实现动态效果。下面提供两种可行方案:
方案一:生成单文件TikZ动画(推荐)
直接生成包含所有时间步数据的LaTeX文件,利用animate包控制帧切换,无需导出多份独立文件。
步骤1:修改Python代码生成动画TeX文件
import numpy as np from scipy.integrate import solve_ivp from matplotlib import pyplot as plt import tikzplotlib # 原模拟逻辑保持不变 M = 10 sites = np.array(range(M)) N = 3 def lotka(t,x): u = x[0:M] v = x[M:] dudt = u-u*u-u*v dvdt = v-u*v-v*v dxdt = np.concatenate((dudt,dvdt)) return dxdt u0 = np.zeros(M) v0 = np.zeros(M) u0[0] = N v0[-1] = N if M%2 == 0: for i in range(int(M/2)): u0[i] = N v0[M-1-i] = N else: for i in range(int(np.floor(M/2))-1): u0[i] = N v0[M-1-i] = N x0 = np.concatenate((u0,v0)) nt = 500 t = np.linspace(0,0.2,nt) x = solve_ivp(lotka,[0,4],x0,t_eval=t) u = np.zeros((nt,M)) v = np.zeros((nt,M)) for i in range(nt): u[i] = x.y.T[i][0:M] v[i] = x.y.T[i][M:] # 生成基础静态图模板 fig = plt.figure() ax = plt.axes() ax.grid() ax.plot(sites, u[0], label='u') ax.plot(sites, v[0], label='v') ax.text(0.05, 0.9, f'time = {t[0]:.4f}', transform=ax.transAxes) ax.legend() base_tikz = tikzplotlib.get_tikz_code(fig) plt.close() # 定义所有时间步的数据宏 u_data = '\n'.join([f" \\def\\u{i}{{{','.join(map(str, u[i]))}}}" for i in range(nt)]) v_data = '\n'.join([f" \\def\\v{i}{{{','.join(map(str, v[i]))}}}" for i in range(nt)]) time_data = '\n'.join([f" \\def\\time{i}{{{t[i]:.4f}}}" for i in range(nt)]) # 构建动画TeX文件 animated_tex = f""" \\documentclass{{standalone}} \\usepackage{{tikz}} \\usepackage{{animate}} \\usepackage{{pgfplots}} \\pgfplotsset{{compat=1.17}} \\begin{{document}} {u_data} {v_data} {time_data} \\begin{{animateinline}}[loop, autoplay, interval=1] """ # 为每个时间步生成绘图帧 for i in range(nt): # 替换基础模板中的数据为当前帧内容 frame_content = base_tikz.replace( f"table {{{','.join(map(str, u[0]))}}}", f"table {{{'\\u'+str(i)}}}" ).replace( f"table {{{','.join(map(str, v[0]))}}}", f"table {{{'\\v'+str(i)}}}" ).replace( f"time = {t[0]:.4f}", f"time = \\time{i}" ) # 提取tikzpicture内部代码 start_idx = frame_content.find('\\begin{tikzpicture}') + len('\\begin{tikzpicture}') end_idx = frame_content.find('\\end{tikzpicture}') frame_tikz = frame_content[start_idx:end_idx].strip() animated_tex += f"\\begin{{tikzpicture}}\n{frame_tikz}\n\\end{{tikzpicture}}\n" if i < nt-1: animated_tex += "\\newframe\n" animated_tex += """ \\end{animateinline} \\end{document} """ # 保存文件 with open('simulation_animation.tex', 'w') as f: f.write(animated_tex) print("动画TeX文件已生成:simulation_animation.tex")
步骤2:编译LaTeX文件
使用支持animate包的编译器,需启用shell escape:
pdflatex -shell-escape simulation_animation.tex
编译后的PDF需在支持动画的阅读器(如Adobe Acrobat、Foxit Reader)中打开才能播放。
方案二:导出多帧静态TikZ文件再整合
如果偏好先导出每个帧的独立TikZ文件,再在LaTeX中组合,可按以下步骤操作:
步骤1:修改Python代码导出单帧TikZ文件
# (原模拟逻辑部分保持不变,直到生成u和v数据) # 逐个导出每一帧的TikZ文件 for i in range(nt): fig = plt.figure() ax = plt.axes() ax.grid() ax.plot(sites, u[i], label='u') ax.plot(sites, v[i], label='v') ax.text(0.05, 0.9, f'time = {t[i]:.4f}', transform=ax.transAxes) ax.legend() tikzplotlib.save(f'frame_{i:03d}.tex') plt.close() print(f"已导出{nt}个帧文件:frame_000.tex 到 frame_{nt-1:03d}.tex")
步骤2:编写LaTeX主文件
创建animation_main.tex:
\\documentclass{standalone} \\usepackage{tikz} \\usepackage{animate} \\begin{document} \\begin{animateinline}[loop, autoplay, interval=1] \\multiframe{500}{i=0+1}{ \\input{frame_\\i.tex} } \\end{animateinline} \\end{document}
注意:\\multiframe{500}{i=0+1}中的500需与你的nt值一致。
步骤3:编译LaTeX文件
同样使用带shell escape的pdflatex编译:
pdflatex -shell-escape animation_main.tex
注意事项
- 确保LaTeX环境已安装
animate、pgfplots、tikz包。 - 调整
interval参数(单位毫秒)可控制动画播放速度。 - 部分轻量PDF阅读器不支持动画效果,需使用专业阅读器查看。
内容的提问来源于stack exchange,提问作者xounamoun
相关产品推荐
相关产品推荐

