4

Is there a way to animate a graph in matplotlib without resorting to the built in animation functions? I find them extremely awkward to use and feel it would be much simpler to just plot a point, wipe the graph, then plot the next point.

I envision something such as:

def f():
     # do stuff here
     return x, y, t

where each t would be a different frame.

I mean, I've tried stuff like using plt.clf(), plt.close() etc. but nothing seems to work.

Lucas
  • 6,869
  • 5
  • 29
  • 44
Astrum
  • 591
  • 3
  • 12
  • 25
  • There is fig=plt.figure("animation") im=plt.imshow(M.reshape(lN,lN),interpolation='none') while {some condition}: M=updateFunc() # update and change the potential of neurons im.set_array(M) # make the image fig.canvas.draw() # draw the image plt.pause(0.1) # slow down the "animation" – mchrgr2000 Feb 18 '22 at 09:30

3 Answers3

4

It is sure possible to animate without FuncAnimation. The purpose of "the enivisioned function", however, is not really clear. In an animation, the time is the independent variable, i.e. for each time step you produce some new data to plot or similar. Therefore the function would take t as an input and give some data back.

import matplotlib.pyplot as plt
import numpy as np

def f(t):
    x=np.random.rand(1)
    y=np.random.rand(1)
    return x,y

fig, ax = plt.subplots()
ax.set_xlim(0,1)
ax.set_ylim(0,1)
for t in range(100):
    x,y = f(t)
    # optionally clear axes and reset limits
    #plt.gca().cla() 
    #ax.set_xlim(0,1)
    #ax.set_ylim(0,1)
    ax.plot(x, y, marker="s")
    ax.set_title(str(t))
    fig.canvas.draw()
    plt.pause(0.1)

plt.show()

Also, it is not clear why you would want to avoid FuncAnimation. The same animation as above can be produced with FuncAnimation as follows:

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

def f(t):
    x=np.random.rand(1)
    y=np.random.rand(1)
    return x,y

fig, ax = plt.subplots()
ax.set_xlim(0,1)
ax.set_ylim(0,1)

def update(t):
    x,y = f(t)
    # optionally clear axes and reset limits
    #plt.gca().cla() 
    #ax.set_xlim(0,1)
    #ax.set_ylim(0,1)
    ax.plot(x, y, marker="s")
    ax.set_title(str(t))

ani = matplotlib.animation.FuncAnimation(fig, update, frames=100)
plt.show()

There is not much changed, you have the same number of lines, nothing really awkward to see here.
Plus you have all the benefits from FuncAnimation when the animation gets more complex, when you want to repeat the animation, when you want to use blitting, or when you want to export it to a file.

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • thanks for this example. I adapted it to use `ax.voxels()` inside `update`, but I get a `RuntimeError: The animation function must return a sequence of Artist objects.` I am wondering why your code works, even though `update` doesn't return anything – crypdick Jul 17 '18 at 22:45
  • 1
    @crypdick If you use `blit=True`, you need to return an iterable of artists to be updated. If you leave `blit=False` (the default), no such list is needed. – ImportanceOfBeingErnest Jul 17 '18 at 22:47
1

it is not clear why you would want to avoid FuncAnimation.

For very simple tests, where you want to check a situation deep inside a loop, it is not easy to set up an animation function.

For instance, I wanted to visualize what happens with this strange sort algorithm: https://arxiv.org/pdf/2110.01111.pdf. To my opinion, the simplest way to do it is:

import numpy as np
import matplotlib.pyplot as plt

def sort(table):
    n = len(table)
    
    for i in range (n):
        for j in range (n):
            if table[i] < table[j]:
                tmp = table[i]
                table[i] = table[j]
                table[j] = tmp
            plt.plot(table, 'ro')
            plt.title(f"i {i} j {j}")
            plt.pause(0.001)
            plt.clf() # clear figure
    return table

n = 50
table =  np.random.randint(1,101,n)
sort(table)
```python

0

I agree that FuncAnimation is awkward to use (not pythonic at all). Actually I believe this function doesn't make too much sense. What is the advantage to have it?

Yes, it introduces an implicit loop that you do not have to write yourself. But the reader cannot fully control this loop and -unless he knows the syntax of the function in advance- he cannot even understand it. Personally I avoid FuncAnimation for reasons of clarity and versatility. Here's a minimal pseudocode example to do that:

fig=plt.figure("animation")
M=zeros((sizeX,sizeY)) # initialize the data (your image)
im=plt.imshow(M) # make an initial plot
########### RUN THE "ANIMATION" ###########################
while {some condition}:
    M=yourfunction() # updates your image
    im.set_array(M) # prepare the new image
    fig.canvas.draw() # draw the image
    plt.pause(0.1) # slow down the "animation"

Very simple and you can see what is happening in your code.

mchrgr2000
  • 61
  • 4