I'm reading output data from some simulations in fortran to make a movie of orbits, after generating a couple graphs. At first, I didn't use blitting for the animation, so while it worked, it was very, very slow.
I originally thought that the animation I wanted lent itself to scatter, since I'd have five series of data with decreasing alphas to create a trailing effect. Here's my original (non-blit) update function:
def animate(frame):
jptx, jpty = jx[frame-3:frame], jy[frame-3:frame]
cptx, cpty = cx[frame-3:frame], cy[frame-3:frame]
eptx, epty = ex[frame-3:frame], ey[frame-3:frame]
gptx, gpty = gx[frame-3:frame], gy[frame-3:frame]
iptx, ipty = ix[frame-3:frame], iy[frame-3:frame]
ax2.clear()
ax2.scatter(jptx, jpty, s=32, c=ablue, marker="s", label='Jupiter')
ax2.scatter(cptx, cpty, s=8, c=ared, marker="o", label='Callisto')
ax2.scatter(eptx, epty, s=8, c=agreen, marker="o", label='Europa')
ax2.scatter(gptx, gpty, s=8, c=ablack, marker="o", label='Ganymede')
ax2.scatter(iptx, ipty, s=8, c=ayellow, marker="o", label='Io')
ax2.set_xlim(-3, 7)
ax2.set_ylim(-3, 4)
animation = animation.FuncAnimation(fig2, animate, interval=0.5, frames=jt.size)
print('Begin saving animation')
animation.save('Tabbys Star.mp4', writer='ffmpeg', fps=60)
print('Animation saved')
plt.show()
Now, when I run the script, a window appears for a fraction of a second, and there is very clearly a yellow circle on the screen, indicating the background is being drawn. However, the window closes immediately after. This is the relevant code for the second attempt. The yellow circle was added in this attempt.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
# j_file = location + 'JUPITER.aei'
# jt, jx, jy, jz = read_data(j_file)
jt, jx, jy, jz = np.random.random([100,4]), np.random.random([100,4]), np.random.random([100,4]), np.random.random([100,4])
# c_file = location + 'CALLISTO.aei'
# ct, cx, cy, cz = read_data(c_file)
ct, cx, cy, cz = np.random.random([100,4]), np.random.random([100,4]), np.random.random([100,4]), np.random.random([100,4])
alphas = [0.25, 0.5, 0.75, 1]
ablue = np.zeros((4, 4))
ablue[:, 2] = 1.0
ablue[:, 3] = alphas
ared = np.zeros((4, 4))
ared[:, 0] = 1.0
ared[:, 3] = alphas
fig2 = plt.figure()
ax2 = fig2.add_subplot(111, aspect='equal')
xdata, ydata = np.zeros((4,)), np.zeros((4,))
jpt, = plt.plot(xdata, ydata, marker='.', ms=32, c=ablue, label='Jupiter')
cpt, = plt.plot(xdata, ydata, marker='.', ms=8, c=ared, label='Callisto')
def init():
ax2.set_xlim(-3, 7)
ax2.set_ylim(-3, 4)
circle = plt.Circle((0, 0), 0.1, color='y')
ax2.add_patch(circle)
for pt in [jpt, cpt]:
pt.set_data(np.zeros((4,)), np.zeros((4,)))
return jpt, cpt
def animate(frame, j, c):
jptx, jpty = jx[frame-3:frame], jy[frame-3:frame]
cptx, cpty = cx[frame-3:frame], cy[frame-3:frame]
j.set_data(jptx, jpty)
c.set_data(cptx, cpty)
return j, c
animation = animation.FuncAnimation(fig2, animate, fargs=(jpt, cpt), interval=0.5, frames=jt.size, init_func=init, blit=True)
print('Begin saving animation')
# animation.save('Tabbys Star.mp4', writer='ffmpeg', fps=60)
print('Animation saved')
plt.show()
I'd also eventually like to add a legend and some axis labels, but I believe that can be done normally.
So what's the problem with animate in the second code snippet?
Thanks
Edited for clarity (again)
Please make sure, that you render it for more than 1 frame, by setting frames to a high value. In the code you posted, the number of frames is not clearly defined, which may cause this problem.
You are confusing plt.plot and plt.scatter here. The error you get would even be produced without any animation.
While plt.plot has arguments color and ms to set the color and markersize respectively, they do not allow to use different values for different points. This is why there exists a scatter plot.
plt.scatter has arguments c and s to set the color and markersize respectively.
So you need to use scatter to obtain differently colored points.
jpt = plt.scatter(xdata, ydata, marker='.', s=32, c=ablue, label='Jupiter')
Then for the animation you would need to adjust your code for the use with scatter since it does not have a .set_data method, but a .set_offsets method, which expects a 2 column array input.
j.set_offsets(np.c_[jptx, jpty])
In total the script would look like
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
jt, jx, jy, jz = [np.random.random([100,4]) for _ in range(4)]
ct, cx, cy, cz = [np.random.random([100,4]) for _ in range(4)]
alphas = [0.25, 0.5, 0.75, 1]
ablue = np.zeros((4, 4))
ablue[:, 2] = 1.0
ablue[:, 3] = alphas
ared = np.zeros((4, 4))
ared[:, 0] = 1.0
ared[:, 3] = alphas
fig2 = plt.figure()
ax2 = fig2.add_subplot(111, aspect='equal')
xdata, ydata = np.zeros((4,)), np.zeros((4,))
jpt = plt.scatter(xdata, ydata, marker='.', s=32, c=ablue, label='Jupiter')
cpt = plt.scatter(xdata, ydata, marker='.', s=8, c=ared, label='Callisto')
def init():
ax2.axis([0,1,0,1])
circle = plt.Circle((0, 0), 0.1, color='y')
ax2.add_patch(circle)
for pt in [jpt, cpt]:
pt.set_offsets(np.c_[np.zeros((4,)), np.zeros((4,))])
return jpt, cpt
def animate(frame, j, c):
jptx, jpty = jx[frame-3:frame], jy[frame-3:frame]
cptx, cpty = cx[frame-3:frame], cy[frame-3:frame]
j.set_offsets(np.c_[jptx, jpty])
c.set_offsets(np.c_[cptx, cpty])
return j, c
animation = animation.FuncAnimation(fig2, animate, fargs=(jpt, cpt),
interval=50, frames=jt.size, init_func=init, blit=True)
plt.show()
Related
I have the following code that should draw a cycloid with animation and save it to a gif
but after running the program, a white square appears that covers everything, I can't find the reason cycloid_animation
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.animation import FuncAnimation, PillowWriter
plt.rcParams['animation.html'] = 'html5'
R = 1
def circle(a, b, r):
# (a,b): the center of the circle
# r: the radius of the circle
# T: The number of the segments
T = 100
x, y = [0]*T, [0]*T
for i,theta in enumerate(np.linspace(0,2*np.pi,T)):
x[i] = a + r*np.cos(theta)
y[i] = b + r*np.sin(theta)
return x, y
# Calculate the cycloid line
thetas = np.linspace(0,4*np.pi,100)
cycloid_x = R*(thetas-np.sin(thetas))
cycloid_y = R*(1-np.cos(thetas))
cycloid_c = R*thetas
fig = plt.figure()
lns = []
trans = plt.axes().transAxes
for i in range(len(thetas)):
x,y = circle(cycloid_c[i], R, R)
ln1, = plt.plot(x, y, 'g-', lw=2)
ln2, = plt.plot(cycloid_x[:i+1] ,cycloid_y[:i+1], 'r-', lw=2)
ln3, = plt.plot(cycloid_x[i], cycloid_y[i], 'bo', markersize=4)
ln4, = plt.plot([cycloid_c[i], cycloid_x[i]], [R,cycloid_y[i]], 'y-', lw=2)
tx1 = plt.text(0.05, 0.8, r'$\theta$ = %.2f $\pi$' % (thetas[i]/np.pi), transform=trans)
lns.append([ln1,ln2,ln3,ln4,tx1])
plt.xlim(0,15)
plt.ylim(0,3)
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.axes().set_aspect('equal')
ani = animation.ArtistAnimation(fig, lns, interval=50)
#ani.save('cycloid_ArtistAnimation.mp4',writer='ffmpeg')
ani.save('cycloid_ArtistAnimation.gif',writer='pillow')
ani
Each time you call plt.axis() you are creating a new axis on top of the figure. Since what you want is to get the current axis and then apply the transformations, after creating the figure you should call plt.gca() to get the current axis and use that instead.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.animation import FuncAnimation, PillowWriter
plt.rcParams['animation.html'] = 'html5'
R = 1
def circle(a, b, r):
# (a,b): the center of the circle
# r: the radius of the circle
# T: The number of the segments
T = 100
x, y = [0]*T, [0]*T
for i,theta in enumerate(np.linspace(0,2*np.pi,T)):
x[i] = a + r*np.cos(theta)
y[i] = b + r*np.sin(theta)
return x, y
# Calculate the cycloid line
thetas = np.linspace(0,4*np.pi,100)
cycloid_x = R*(thetas-np.sin(thetas))
cycloid_y = R*(1-np.cos(thetas))
cycloid_c = R*thetas
fig = plt.figure()
lns = []
trans = plt.gca().transAxes #<=== HERE
for i in range(len(thetas)):
x,y = circle(cycloid_c[i], R, R)
ln1, = plt.plot(x, y, 'g-', lw=2)
ln2, = plt.plot(cycloid_x[:i+1] ,cycloid_y[:i+1], 'r-', lw=2)
ln3, = plt.plot(cycloid_x[i], cycloid_y[i], 'bo', markersize=4)
ln4, = plt.plot([cycloid_c[i], cycloid_x[i]], [R,cycloid_y[i]], 'y-', lw=2)
tx1 = plt.text(0.05, 0.8, r'$\theta$ = %.2f $\pi$' % (thetas[i]/np.pi), transform=trans)
lns.append([ln1,ln2,ln3,ln4,tx1])
plt.xlim(0,15)
plt.ylim(0,3)
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.gca().set_aspect('equal') #<=== And HERE
ani = animation.ArtistAnimation(fig, lns, interval=50)
#ani.save('cycloid_ArtistAnimation.mp4',writer='ffmpeg')
ani.save('cycloid_ArtistAnimation.gif',writer='pillow')
I have an array of shape(512,512).
Looks like, (row=x, column=y, density=z=the number of the array)
[[0.012825 0.020408 0.022976 ... 0.015938 0.02165 0.024357]
[0.036332 0.031904 0.025462 ... 0.031095 0.019812 0.024523]
[0.015831 0.027392 0.031939 ... 0.016249 0.01697 0.028686]
...
[0.024545 0.011895 0.022235 ... 0.033226 0.03223 0.030235]]
I had already drawn it into a 2D density plot. My goal is to find the center of the circle and draw a vertical and horizontal cross-section in one figure.
Now, I have the trouble to find the center of the circle and combine two cross-sections in one figure.
Please help.
This is my code:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import scipy.ndimage
data = pd.read_csv('D:/BFP.csv', header=None)
# create data
data = np.array(data)
print(data)
#plot data
side = np.linspace(-1.5,1.5,512)
x,y = np.meshgrid(side,side)
z = [[data[i][j] for i in range(len(data[0]))]for j in range(len(data))]
#-- Extract the line...
# Make a line with "num" points...
x0, y0 = 270, 0 # These are in _pixel_ coordinates!!
x1, y1 = 270, 500
num = 512
x_, y_ = np.linspace(x0, x1, num), np.linspace(y0, y1, num)
# Extract the values along the line, using cubic interpolation
zi = scipy.ndimage.map_coordinates(z, np.vstack((x_,y_)))
#-- Plot...
fig, axes = plt.subplots(nrows=2)
axes[0].imshow(z,origin='lower')
axes[0].plot([x0, x1], [y0, y1], 'ro-')
#axes[0].axis('image')
axes[1].plot(zi)
plt.savefig('D:/vertical.png')
plt.show()
image here:
I cannot help you with finding the center of the circle, but you can create a nice visualization of the cross section by creating 3 axes in a grid. Usually, I would use GridSpec for this, but imhsow has a tendency to mess up the relative size of the axes to maintain square pixels. Thankfully, the AxesGrid toolkit can help.
The base of the code is inspired by this matplotlib example.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
from scipy.stats import multivariate_normal
import scipy
fig, main_ax = plt.subplots(figsize=(5, 5))
divider = make_axes_locatable(main_ax)
top_ax = divider.append_axes("top", 1.05, pad=0.1, sharex=main_ax)
right_ax = divider.append_axes("right", 1.05, pad=0.1, sharey=main_ax)
# make some labels invisible
top_ax.xaxis.set_tick_params(labelbottom=False)
right_ax.yaxis.set_tick_params(labelleft=False)
main_ax.set_xlabel('dim 1')
main_ax.set_ylabel('dim 2')
top_ax.set_ylabel('Z profile')
right_ax.set_xlabel('Z profile')
x, y = np.mgrid[-1:1:.01, -1:1:.01]
pos = np.empty(x.shape + (2,))
pos[:, :, 0] = x; pos[:, :, 1] = y
rv = multivariate_normal([-0.2, 0.2], [[1, 1.5], [0.25, 0.25]])
z = rv.pdf(pos)
z_max = z.max()
cur_x = 110
cur_y = 40
main_ax.imshow(z, origin='lower')
main_ax.autoscale(enable=False)
right_ax.autoscale(enable=False)
top_ax.autoscale(enable=False)
right_ax.set_xlim(right=z_max)
top_ax.set_ylim(top=z_max)
v_line = main_ax.axvline(cur_x, color='r')
h_line = main_ax.axhline(cur_y, color='g')
v_prof, = right_ax.plot(z[:,int(cur_x)],np.arange(x.shape[1]), 'r-')
h_prof, = top_ax.plot(np.arange(x.shape[0]),z[int(cur_y),:], 'g-')
plt.show()
Just for fun, you can even make it interactive
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
from scipy.stats import multivariate_normal
import scipy
fig, main_ax = plt.subplots(figsize=(5, 5))
divider = make_axes_locatable(main_ax)
top_ax = divider.append_axes("top", 1.05, pad=0.1, sharex=main_ax)
right_ax = divider.append_axes("right", 1.05, pad=0.1, sharey=main_ax)
# make some labels invisible
top_ax.xaxis.set_tick_params(labelbottom=False)
right_ax.yaxis.set_tick_params(labelleft=False)
main_ax.set_xlabel('dim 1')
main_ax.set_ylabel('dim 2')
top_ax.set_ylabel('Z profile')
right_ax.set_xlabel('Z profile')
x, y = np.mgrid[-1:1:.01, -1:1:.01]
pos = np.empty(x.shape + (2,))
pos[:, :, 0] = x; pos[:, :, 1] = y
rv = multivariate_normal([-0.2, 0.2], [[1, 1.5], [0.25, 0.25]])
z = rv.pdf(pos)
z_max = z.max()
main_ax.imshow(z, origin='lower')
main_ax.autoscale(enable=False)
right_ax.autoscale(enable=False)
top_ax.autoscale(enable=False)
right_ax.set_xlim(right=z_max)
top_ax.set_ylim(top=z_max)
v_line = main_ax.axvline(np.nan, color='r')
h_line = main_ax.axhline(np.nan, color='g')
v_prof, = right_ax.plot(np.zeros(x.shape[1]),np.arange(x.shape[1]), 'r-')
h_prof, = top_ax.plot(np.arange(x.shape[0]),np.zeros(x.shape[0]), 'g-')
def on_move(event):
if event.inaxes is main_ax:
cur_x = event.xdata
cur_y = event.ydata
v_line.set_xdata([cur_x,cur_x])
h_line.set_ydata([cur_y,cur_y])
v_prof.set_xdata(z[:,int(cur_x)])
h_prof.set_ydata(z[int(cur_y),:])
fig.canvas.draw_idle()
fig.canvas.mpl_connect('motion_notify_event', on_move)
plt.show()
NB: the lag is just due to the convertion in gif, the update is much smoother on my machine
This is a double question. My main goal is to create an animated 3D plot. I started creating the same plot, but in 2D. But the animation does not work, and I don’t know why. This is the code:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
%matplotlib nbagg
'''
Each one of those are list of numbers:
x_earth, y_earth, z_earth, x_ryu, y_ryu, z_ryu, x_hay,y_hay,z_hay, vel, dist, t
'''
fig = plt.figure(figsize= (8,4))
ax1 = fig.add_subplot (121)
ax1.grid (True)
ax1.plot (0,0,'yo', markersize=20, label='Sun' )
ax1.set_xlim(min (min (x_earth), min(x_ryu), min(x_hay)), max (max (x_earth), max(x_ryu), max(x_hay)))
ax1.set_ylim(min (min (y_earth), min(y_ryu), min(y_hay)), max (max (y_earth), max(y_ryu), max(y_hay)))
pt1, = ax1.plot ([],[], 'bo', label='Earth')
pt2, = ax1.plot ([],[],'ko', label='Ryugu')
pt3, = ax1.plot ([],[], 'r^', label='Hayabusa 2')
l3, = ax1.plot ([],[], 'r--')
#ax1.legend()
ax2 = fig.add_subplot (122)
ax2.grid(True)
ax2.set_xlim(0, max (t))
ax2.set_ylim(0, max (max (vel), max(dist)))
l4, = ax2.plot ([],[], 'b-', label='Rendezvous Distance')
l5, = ax2.plot ([],[], 'g--', label = 'Hayabusa velocity')
ax2.legend()
def init():
pt1.set_data([],[])
pt2.set_data([],[])
pt3.set_data([],[])
l3.set_data([],[])
l4.set_data([],[])
l5.set_data([],[])
return (pt1,pt2,pt3,l3,l4,l5,)
def animate(i):
pt1.set_data(x_earth[i],y_earth[i])
pt2.set_data(x_ryu[i],y_ryu[i])
pt3.set_data(x_hay[i],y_hay[i])
l3.set_data(t[:i],dist[:i])
l4.set_data(t[:i],dist[:i])
l5.set_data(t[:i],vel[:i])
return (pt1,pt2,pt3,l3,l4,l5,)
ani = FuncAnimation (fig, animate, fargs=(pt1,pt2,pt3,l3,l4,l5),frames =len(t),init_func=init,interval=25, blit=True)
plt.show()
Then, I would like to transform the left subplot into a 3D plot, by adding a third column to the data. But I don’t know how to do that.
I need to animate something rather simple but I do need as well a slider to let the user interactively changes the parameters of the animation. I'd like it to happen online; i.e. if the user changes a parameter while the animation is playing, the animation should transit smoothly from its old dynamics to its new one.
So far I've written a function that takes arguments and makes an animation. But it's not interactive in the sense I mentioned before. There are no sliders or anything really interactive in my code. Nevertheless, the animation part is running smoothly at least.
Here is a simplified version of my code: A point revolves around the center with a specified distance r from the center and an angular velocity w. User can give them as arguments to see the animation. (If you saw something in the code that is never used don't bother yourself with it, it is probably because I forgot to trim it from the original code with is much longer.)
import numpy as np
%matplotlib notebook
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def simplified_code(w,r):
fps = 36
M = int(.75*fps*2*np.pi/w)
T_final = 2*np.pi/w*16
def positions(t):
x = r*np.cos(w*t)
y = r*np.sin(w*t)
return x,y
fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal', autoscale_on=False, )
ax.grid()
# position
x_e, y_e = [], []
# trajectory and center
traj_e, = plt.plot([],[],'-g',lw=1)
e, = plt.plot([], [], 'ok')
# time
time_text = ax.text(0.02, 0.95, '', transform=ax.transAxes)
def init():
ax.set_xlim(-(r+0.5), (r+0.5))
ax.set_ylim(-(r+0.5), (r+0.5))
ax.plot([0], ms=7, c='k',marker='o')
return d,e,traj_e
def update(frame):
x,y = positions(frame)
x_e.append(x)
y_e.append(y)
traj_e.set_data(x_e[-M:], y_e[-M:])
e.set_data(x, y)
time_text.set_text('time = %.1f' % frame)
return traj_d,traj_e,d,e, orb
return FuncAnimation(fig, update, frames=np.linspace(0, T_final, T_final*fps),
init_func=init, blit=True, interval=1./36*1000)
Note that it's possible to stop the animation, change the parameters via a slider and rerun it. I want to avoid this pause in the animation. I'd appreciate any help.
Thanks to #ImportanceOfBeingErnest I managed to combine update function of the animation and the one with the sliders:
import numpy as np
%matplotlib notebook
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.widgets import Slider
fig = plt.figure(figsize=(6,7))
ax = fig.add_subplot(111, aspect='equal', autoscale_on=False, position=[.15,.15,.75,.75] )
ax.grid()
w = 2
r = 1
fps = 36
M= 1024#
T_final = 256
x_e, y_e = [], []
orb_x, orb_y = [], []
# trajectories
traj_e, = ax.plot(x_e,y_e,'-g',lw=1)
# center
e, = ax.plot([], [], 'ok')
# orbit
orb, = ax.plot([], [], '.r',ms=1)
# time
time_text = ax.text(0.02, 0.95, '', transform=ax.transAxes)
def positions(t):
x = r*np.cos(w*t) # epicycle
y = r*np.sin(w*t) # epicycle
return x,y
def orbit(r):
phi = np.linspace(0, 2*np.pi, 360)
orb_x = r*np.cos(phi)
orb_y = r*np.sin(phi)
return orb_x,orb_y
def init():
ax.plot([0], ms=7, c='k',marker='o')
return e,traj_e
def update(t):
global r, w
w = s_w.val
r = s_r.val
ax.set_xlim(-(r)*1.1, (r)*1.1)
ax.set_ylim(-(r)*1.1, (r)*1.1)
x,y = positions(t)
x_e.append(x)
y_e.append(y)
traj_e.set_data(x_e[-M:-1], y_e[-M:-1])
orb.set_data(orbit(r))
e.set_data(x, y)
time_text.set_text('time = %.1f' % t)
return traj_e,e, orb
ax_w = plt.axes([0.1, 0.05, 0.35, 0.03])#, facecolor=axcolor)
ax_r = plt.axes([0.55, 0.05, 0.35, 0.03])#, facecolor=axcolor)
s_w = Slider(ax_w, r'$\omega$', -20, 20, valinit=w, valstep=0.2)
s_r = Slider(ax_r, r'r', 0, 5, valinit=r, valstep=0.2)
s_w.on_changed(update)
s_r.on_changed(update)
def anim():
fig.canvas.draw_idle()
return FuncAnimation(fig, update, frames=np.linspace(0, T_final, T_final*fps),
init_func=init, blit=True, interval=30)
anim()
Using this piece of code I can change the values of r and w without pausing or restarting the animation from scratch. Another problem appears with this code though which is that the point jumps to some random position on the circle and then jumps back the expected trajectory. I'd address it in another question.
I have the following code that produces an animation of drawing a circle.
from math import cos, sin
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def update_plot(num, x, y, line):
line.set_data(x[:num], y[:num])
line.axes.axis([-1.5, 1.5, -1.5, 1.5])
return line
def plot_circle():
x = []
y = []
for i in range(100):
x.append(cos(i/10.0))
y.append(sin(i/10.0))
fig, ax = plt.subplots()
line, = ax.plot(x, y, color = "k")
ani = animation.FuncAnimation(fig, update_plot, len(x), fargs=[x, y, line], interval = 1, blit = False)
plt.show()
plot_circle()
The line is longer than a full lap, and so to be able to still see the drawing when the line overlaps, I would like a marker that shows what is being drawn. I tried to add a scatter plot into the update call, like
scat = plt.scatter(0, 0)
ani = animation.FuncAnimation(fig, update_plot, len(x), fargs=[x, y, line, scat], interval = 1, blit = False)
and try to update the position of the scatter-plot point using x[num] and y[num] in update_plot without success. How can I achieve this effect?
You need to return scat in update_plot().
Here is another method, draw the line with markevery argument:
line, = ax.plot(x, y, "-o", color="k", markevery=100000)
reverse the points order:
line.set_data(x[:num][::-1], y[:num][::-1])
for example:
import numpy as np
import pylab as pl
t = np.linspace(0, 2, 100)
x = np.cos(t)
y = np.sin(t)
pl.plot(x[::-1], y[::-1], "-o", markevery=10000)
outputs:
I ended up finding a way to add the scatter plot to the same animation. The key was to use scat.set_offsets to set the data. The changes that are needed is as follows:
def update_plot(num, x, y, line, scat):
# ...
scat.set_offsets([x[num - 1], y[num - 1]])
return line, scat
def plot_circle():
# ...
scat = ax.scatter([0], [0], color = 'k') # Set the dot at some arbitrary position initially
ani = animation.FuncAnimation(fig, update_plot, len(x), fargs=[x, y, line, scat], interval = 1, blit = False)
plt.show()