You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 17:15:35