4

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?

5
  • For an example using a loop see e.g. this question, but there are hundreds of other examples around. However, this sounds like a typical XYproblem. Could you please tell exactly what the purpose of this should be? Commented May 26, 2017 at 8: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. Commented May 26, 2017 at 8: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? Commented May 26, 2017 at 8: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 ;). Commented May 26, 2017 at 8: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. Commented May 26, 2017 at 9:37

1 Answer 1

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()
Sign up to request clarification or add additional context in comments.

1 Comment

Imo this is not an answer to the question, the ask was for a push-driven animation, not a pull-driven approach such as TimedAnimation subclasses

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.