matplotlib 将动画转换为内存文件或函数

1yjd4xko  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(85)

我正在创建一个matplotlib动画,根据用户输入显示在flask应用程序上。matplotlib脚本类似于:

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np

# Horizontal bar plot with gaps
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)  #convert to array wont work with list
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=100000)

# To save the animation using Pillow as a gif
writer = animation.PillowWriter(fps=1,
                                 metadata=dict(artist='Me'),
                                 bitrate=1800)
ani.save('scatter.gif', writer=writer)

字符串

是否可以将gif保存到内存文件中,而不是保存为gif?

k97glaaz

k97glaaz1#

  • 您可以将文件保存为tempfile,使用io.BytesIO将其加载到内存中,然后删除该文件。
  • 使用buf = io.BytesIO()ani.save(buf, writer=writer)无法将动画直接保存到缓冲区,因为ani.save不接受BytesIO作为路径。
  • 下面的代码示例是完全可执行的。
  • python 3.9.18flask 2.2.2matplotlib 3.7.2numpy 1.21.5中测试。
from flask import Flask, Response
import io
import matplotlib.animation as animation
import matplotlib.pyplot as plt
import numpy as np
import os
import tempfile

app = Flask(__name__)

@app.route("/")
def index():
    return """
    <html>
        <body>
            <img src="/gif" alt="animation">
        </body>
    </html>
    """

@app.route("/gif")
def gif():
    # Generate the GIF data and store it in a BytesIO object (buf)
    # Here you should call the function or code that generates the GIF and returns the BytesIO object.
    # For example, you can call a function that generates the matplotlib animation and returns buf.
    buf = generate_gif()  # replace this with your code that generates the GIF

    # Return the GIF data as a response with the correct content type
    return Response(buf.getvalue(), content_type="image/gif")

def generate_gif():

    # Horizontal bar plot with gaps
    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)  # convert to array won't work with list
    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=100000)

    # Save the animation to a temporary file with a '.gif' suffix
    with tempfile.NamedTemporaryFile(delete=False, suffix=".gif") as temp_file:
        writer = animation.PillowWriter(fps=1, metadata=dict(artist="Me"), bitrate=1800)
        ani.save(temp_file.name, writer=writer)

        # Read the file contents into a BytesIO object
        temp_file.seek(0)
        buf = io.BytesIO(temp_file.read())

    # Now buf contains the gif data, and you can use buf.getvalue() to access it.
    # Don't forget to delete the temporary file
    os.remove(temp_file.name)

    return buf

if __name__ == "__main__":
    app.run(debug=True)

字符串


的数据
根据OP基于Given a BytesIO buffer, generate img tag in html的评论进行更新。

temp_file.seek(0)
buf = io.BytesIO(temp_file.read())
gif = base64.b64encode(buf.getbuffer()).decode("ascii")  # return gif

# on the html side:
<img src='data:image/png;base64,{{buf}}' class="responsiveImage"/>

相关问题