如何将Matplotlib动画保存到内存文件而非本地GIF文件?
将Matplotlib动画保存到内存并在Flask中展示
当然可以,你可以用Python的io.BytesIO类将GIF动画直接写入内存,无需保存到本地文件。下面是修改后的代码,以及结合Flask的完整实现:
1. 修改Matplotlib动画代码(写入内存)
替换原代码中保存到本地文件的部分,改用BytesIO存储动画内容:
import matplotlib.pyplot as plt import matplotlib.animation as animation import numpy as np import io # 新增导入 # 原有的图形和动画定义部分不变 fig, ax = plt.subplots() ax.get_yaxis().set_visible(False) ax.spines[['top', 'bottom','left','right']].set_visible(False) y2 = [20,20,20,20,20,20,20] y3 = np.array(y2) x2 = [20,15,14,13, 12,11,10] x3 = np.array(x2) year = ["2014","2015","2016","2017","2018","2019","2020"] yr2 = np.array(year) def animate(i): ax.clear() ax.set_ylim(16, 24) ax.barh(20, 60, 4 ) ax.plot(60, 18, marker=6, markersize=18, clip_on=False,) ax.annotate(r"$\bf" + str(2013) +"$" + f" ({60})", (60 , 18), xytext=(0, -25), size=8, textcoords='offset points', ha='center', va='bottom') ax.barh(y3[i], x3[i], 4, color='c') ax.plot(x3[i], y3[i]+2, color='c', marker=7, markersize=18, clip_on=False,) ax.annotate(r"$\bf" + str(yr2[i]) +"$" + f" ({x3[i]})", (x3[i] , y3[i]+2), xytext=(0, 15), size=8, color='c', textcoords='offset points', ha='center', va='bottom') ani = animation.FuncAnimation(fig, animate, repeat=False, frames=len(x3), interval=1000) # 调整间隔为1秒,原100秒间隔过久 # 写入内存而非本地文件 writer = animation.PillowWriter(fps=1, metadata=dict(artist='Me'), bitrate=1800) buf = io.BytesIO() # 创建内存文件对象 ani.save(buf, writer=writer) buf.seek(0) # 将文件指针移到开头,方便后续读取 plt.close(fig) # 关闭图形,避免Flask长期运行内存泄漏
2. Flask路由实现(返回内存中的GIF)
将上述代码整合到Flask路由中,直接返回内存中的GIF内容:
from flask import Flask, Response app = Flask(__name__) @app.route('/animated-bar-chart') def animated_bar_chart(): # 复制上面的动画生成逻辑 import matplotlib.pyplot as plt import matplotlib.animation as animation import numpy as np import io fig, ax = plt.subplots() ax.get_yaxis().set_visible(False) ax.spines[['top', 'bottom','left','right']].set_visible(False) y2 = [20,20,20,20,20,20,20] y3 = np.array(y2) x2 = [20,15,14,13, 12,11,10] x3 = np.array(x2) year = ["2014","2015","2016","2017","2018","2019","2020"] yr2 = np.array(year) def animate(i): ax.clear() ax.set_ylim(16, 24) ax.barh(20, 60, 4 ) ax.plot(60, 18, marker=6, markersize=18, clip_on=False,) ax.annotate(r"$\bf" + str(2013) +"$" + f" ({60})", (60 , 18), xytext=(0, -25), size=8, textcoords='offset points', ha='center', va='bottom') ax.barh(y3[i], x3[i], 4, color='c') ax.plot(x3[i], y3[i]+2, color='c', marker=7, markersize=18, clip_on=False,) ax.annotate(r"$\bf" + str(yr2[i]) +"$" + f" ({x3[i]})", (x3[i] , y3[i]+2), xytext=(0, 15), size=8, color='c', textcoords='offset points', ha='center', va='bottom') ani = animation.FuncAnimation(fig, animate, repeat=False, frames=len(x3), interval=1000) writer = animation.PillowWriter(fps=1, metadata=dict(artist='Me'), bitrate=1800) buf = io.BytesIO() ani.save(buf, writer=writer) buf.seek(0) plt.close(fig) # 返回GIF响应,指定正确的MIME类型 return Response(buf.getvalue(), mimetype='image/gif') if __name__ == '__main__': app.run(debug=True)
关键说明
io.BytesIO()创建了一个在内存中读写的类文件对象,完全替代本地文件路径。buf.seek(0)必须调用,否则读取时会从文件末尾开始,返回空内容。plt.close(fig)很重要,避免Flask持续运行时积累未关闭的Matplotlib图形,导致内存泄漏。- 路由返回
Response对象时,设置mimetype='image/gif'让浏览器正确识别内容类型。
内容的提问来源于stack exchange,提问作者ruthpozuelo
相关产品推荐
相关产品推荐

