Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

matplotlib FuncAnimation clear plot each repeat cycle

The code below works, but I think is overplotting the original points each repeat cycle. I want it to start from the origin, each repeat cycle, with a clear plot. Amongst many approaches to fixing this, I have tried inserting ax.clear() in both the init and update functions; not effective. I have left in the code what I thought would reset the ln, artist to having an empty set; again this is not the solution I am looking for. I would appreciate some guidance on what the correct way to reinitiate each cycle is in this toy example so that, when applied to my more complex problem, I don't incur cumulative penalties. This works fine in terms of refreshing if passing an array...Thanks for any help.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, writers
#from basic_units import radians
# # Set up formatting for the movie files
# Writer = writers['ffmpeg']
# writer = Writer(fps=20, metadata=dict(artist='Llew'), bitrate=1800)

#Polar stuff
fig = plt.figure(figsize=(10,8))
ax = plt.subplot(111,polar=True)
ax.set_title("A line plot on a polar axis", va='bottom')
ax.set_rticks([0.5, 1, 1.5, 2])  # fewer radial ticks
ax.set_facecolor(plt.cm.gray(.95))
ax.grid(True)
xT=plt.xticks()[0]
xL=['0',r'$\frac{\pi}{4}$',r'$\frac{\pi}{2}$',r'$\frac{3\pi}{4}$',\
    r'$\pi$',r'$\frac{5\pi}{4}$',r'$\frac{3\pi}{2}$',r'$\frac{7\pi}{4}$']
plt.xticks(xT, xL)
r = []
theta = []
# Animation requirements.
ln, = plt.plot([], [], 'r:',
                    markersize=1.5,
                    alpha=1,
                    animated=True)

def init():
    ax.set_xlim(0, 2)
    ax.set_ylim(0, 2)
    return ln,

def update(frame):
    r.append(frame)
    theta.append(5*np.pi*frame)
    ln.set_data(theta, r)
    return ln,

ani = FuncAnimation(fig, update, frames=np.linspace(0,2,400),
                    init_func=init, interval=10, blit=True,repeat=True)

plt.show()

I tried to reset the lists (and with arrays also) using this somewhat crude approach, which wiped the list, but did not re-initiate the cycle.

def update(frame,r,theta):
    r.append(frame)
    theta.append(5*np.pi*frame)
    if len(r)>=400:
        r = [0]
        theta=[0]
    ln.set_data(theta, r)
    return ln,

In contrast, this does work as intended...

for i in range(25):
    r.append(i)
    print('len(r)',len(r), r)
    if len(r) >=10:
        r = []
        print('if r>=10:',r)
    print('Post conditional clause r',len(r),r)

This led me to try the following, noting that passing the internal (r,theta) within the update() outside requires declaring it as a global variable. With the following code, the plot now resets each cycle instead of overplotting. My sense is that this is a rather long way around a simple procedure -- any improvements gratefully accepted.

#This solution also works
def update(frame):
        r.append(frame)
        theta.append(5*np.pi*frame)
        if len(r)>=400:
            global r
            r = []
            global theta
            theta=[]
        ln.set_data(theta, r)
        return ln,
like image 507
Time Lord Avatar asked Nov 09 '17 01:11

Time Lord


1 Answers

If I understand your code and your question, you want to display only one point at each frame of the animation, is that correct?

If so, your problem is simply that you are appending each new point to all previous points in the function update(). Instead, simply update the data coordinates, like so:

def update(frame):
    r = frame
    theta = 2*np.pi*frame
    ln.set_data(theta, r)
    return ln,

enter image description here

EDIT Let's see if I get this right this time around.

You could choose to only show the last N points like so:

N=10
def update(frame):
    r.append(frame)
    theta.append(2*np.pi*frame)
    ln.set_data(theta[-N:], r[-N:])
    return ln,

enter image description here

or you can append N points to your array, then reset to an empty array. I think that might be what you were trying to do. Here, you have to be careful. If you simply do r = [] then you change which object r references to, and that breaks the animation. What you need to do is change the content of the array with the syntax r[:] = [].

def update(frame):
    r_ = frame
    theta_ = 2*np.pi*frame
    if len(r)>N:
        r[:] = [r_]
        theta[:] = [theta_]
    else:    
        r.append(r_)
        theta.append(theta_)
    ln.set_data(theta, r)
    return ln,

enter image description here

like image 121
Diziet Asahi Avatar answered Sep 28 '22 23:09

Diziet Asahi