3

I want to create a matplotlib animation, but instead of having matplotlib call me I want to call matplotlib. For example I want to do this:

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

def update(frame):
    plt.scatter(random(),random())

fig, ax = plt.subplots()
ani = FuncAnimation(fig, update, interval=340, repeat=True)
ani.save("my.mov", "avconv")

Like this:

def update():
    plt.scatter(random(),random())

fig, ax = plt.subplots()
ani = MadeUpSubClassPassiveAnimation(fig)

while True:
  update()
  ani.update()
  # do other stuff ...

ani.save("my.mov", "avconv") 

I realize I could drive a live plot like this:

def update():
  plt.scatter(x, y)
  plt.pause(0.01)

fig, ax = plt.subplots()
plt.ion()

while True:
  update()
  time.sleep(1)

But AFAIK I need to use Animation for the save() functionality. So, is it possible to drive Animation rather than have it drive me? If so how?

spinkus
  • 7,694
  • 4
  • 38
  • 62
  • For an example using a loop see e.g. [this question](https://stackoverflow.com/questions/40126176/fast-live-plotting-in-matplotlib-pyplot), but there are hundreds of other examples around. However, this sounds like a typical [XYproblem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Could you please tell exactly what the purpose of this should be? – ImportanceOfBeingErnest May 26 '17 at 08:28
  • 1
    It's not an XYProblem. Why? Because in terms of code structure it make more sense. I want the matplotlib view to be just another output handler. Like a view in Model/View pattern. My model does something, then it notifies handlers, one of which may or may not be a matplotlib animation. – spinkus May 26 '17 at 08:37
  • See, we're in the middle of the typical XYproblem discussion. ;-) A while loop does not notify anyone of anything. Can you please write the question in a way that it becomes clear what you need? – ImportanceOfBeingErnest May 26 '17 at 08:41
  • 1
    No sorry I can't. The form of the question as written above succinctly gets to the very heart of what I want, without any distractions / bloat. I have had this discussion with many ppl on SO, and my view on how to write question has not changed ;). – spinkus May 26 '17 at 08:46
  • @ImportanceOfBeingErnest AFAICT my question is not a duplicate of those questions, because those questions don't use Animation. I have updated my question to try explain a little better. – spinkus May 26 '17 at 09:37

1 Answers1

1

An Animation is run when being saved. This means that the animation needs to reproducibly give the same result when being run twice (once for saving, once for showing). In other words, the animation needs to be defined in terms of successive frames. With this requirement, any animation can be constructed using a callback on either a function (FuncAnimation) or on a list of frames (ArtistAnimation).

The example from the question could be done with an ArtistAnimation (in order not to have different random numbers for the saved and the shown animation, respectively):

from random import random

import matplotlib.animation
import matplotlib.pyplot as plt

def update(frame: int) -> list[matplotlib.artist.Artist]:
    sc = ax.scatter(random(), random())
    return [sc]

fig, ax = plt.subplots()

artists = []

for i in range(10):
    sc = update(i)
    artists.append(sc)

# If you want previous plots to be present in all frames, add:
# artists = [[j[0] for j in artists[:i+1]] for i in range(len(artists))]
  
ani = matplotlib.animation.ArtistAnimation(fig, artists, interval=100)
ani.save(__file__ + ".gif", writer="imagemagick") 
plt.show()
Intrastellar Explorer
  • 3,005
  • 9
  • 52
  • 119
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712