Matplotlib ArtistAnimation: Plot entire figure in each step

旧巷老猫 提交于 2020-06-11 15:40:22

问题


I have an existing function I use for plotting, which I call repeatedly in my program. I want to use matplotlib's ArtistAnimation to save each plot as an "artist" that is shown in one step of the animation.

I know how to use ArtistAnimation to show individual elements of the plot in the animation, but not the entire plot.

Here's a simplified example:

import random

def my_plot():
    fig, ax = plt.subplots()
    ax.plot([random.randrange(10), random.randrange(10)], [random.randrange(10), random.randrange(10)])
    ax.plot([random.randrange(10), random.randrange(10)], [random.randrange(10), random.randrange(10)])
    plt.show()
    return ax

ims = []
fig = plt.figure()
for _ in range(5):
    ax = my_plot()
    ims.append((ax,))
ani = animation.ArtistAnimation(fig, ims, repeat=False)
ani.save('im.mp4', metadata={'artist':'Guido'})

This runs without error, but the resulting video is just blank. The same happens if I return a list of the artists created by ax.plot().

I assume the problem is that I'm calling plt.figure/plt.subfigure multiple times. But I'm not sure how to avoid that. Do I need to create one figure up front and pass that to each call of my_plot? Seems a bit ugly.


回答1:


Instead of saving the axes, you need to save the plots as a list. (Or maybe you don't want to do this and want to save the axes? If that's the case, let me know and I'll delete this. I don't think saving the axes will work though, since the animation works by setting the saved items within a figure visible and invisible, and neither the axes nor the figure will hide/reveal a subset of the plots for each frame in this way.)

import matplotlib.pyplot as plt
from matplotlib import animation
import random

def my_plot(ax):
    p0, = ax.plot([random.randrange(10), random.randrange(10)], [random.randrange(10), random.randrange(10)])
    p1, = ax.plot([random.randrange(10), random.randrange(10)], [random.randrange(10), random.randrange(10)])
    return [p0, p1]   # return a list of the new plots

ims = []
fig = plt.figure()
ax = fig.add_subplot(111)  # fig and axes created once
for _ in range(10):
    ps = my_plot(ax)
    ims.append(ps)      # append the new list of plots
ani = animation.ArtistAnimation(fig, ims, repeat=False)
ani.save('im.mp4', metadata={'artist':'Guido'})

GIF below, but here is some vertical spacing so you can scroll the annoying flashing lines of the page while reading the code

.
.
.
.
.
.
.
.
.
.
.
.
.
.




回答2:


Thanks to tom's answer, I found the main reasons why my animations didn't work and only showed the first frame: I called plt.show() in each iteration. Apparently, after the first call, the animations stop working. Removing plt.show() and only creating one figure solved the problem:

import matplotlib.pyplot as plt
from matplotlib import animation
import random

def my_plot():
    patch = []
    patch.extend(plot([random.randrange(10), random.randrange(10)], [random.randrange(10), random.randrange(10)]))
    patch.extend(plt.plot([random.randrange(10), random.randrange(10)], [random.randrange(10), random.randrange(10)]))
    # no plt.show() here!
    return patch

ims = []
fig = plt.figure()   # fig created only once
for _ in range(10):
    patch = my_plot()
    ims.append(patch)  
ani = animation.ArtistAnimation(fig, ims, repeat=False)
ani.save('im.mp4', metadata={'artist':'Guido'})

Not sure how I could both plot and show the plots directly and create an animation. Maybe using plt.draw() instead? But that doesn't show anything in my PyCharm IDE... Anyways, I can live with either or.



来源:https://stackoverflow.com/questions/61652069/matplotlib-artistanimation-plot-entire-figure-in-each-step

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!