I am just starting a small particle simulator I wish to expand to solve some physics problems but I have a problem trying to animate them. Essentially depending on what kind of random distribution you choose the particles will "oscillate" in an area of a given length. I want to show the "history" of the particle at say the 10 previous steps.
Here is the code
from numpy import *
import matplotlib.pyplot as plt
import pylab
import time
pylab.ion()
N = 10
r = random.randint(-100,100,2*N).reshape(N,2)
line, = plt.plot(r[:,0], r[:,1],'o')
for i in range(100000):
newdatax = r[:,0] + random.rand(N)
newdatay = r[:,1] + random.rand(N)
line.set_ydata(newdatay)
line.set_xdata(newdatax)
plt.title("At timestep: %d" %i)
plt.hold(True)
plt.draw()
time.sleep(1.0/30)
What I want is for the line update to NOT clear the canvas and redraw at every iteration, I just want it to do that for say, every 10th frame (iteration), this will make it easier for me to track the particles visually.
There is another thing I wish to implement but it is not strictly necessary, is it possible to draw a box (square) or a circle or a triangle around each "o"? Such that the point is centered in that box/circle/triangle? This would again make it much easier to track particles. It would be even nicer if I could dictate which "o" (point) gets this property (square).
Try the animation
module. Also see this awesome tutorial, Matplotlib animate over an image (mostly a copy and past of my answer to Animate drawing networkx edges)
To get the time lag you want, you need to set up a history data structure, something like:
from matplotlib import animation
fig = figure()
N = 10
r = random.randint(-100,100,2*N).reshape(N,2)
line, = plt.plot(r[:,0], r[:,1],'o')
lag_len = 10
history_x = np.zeros((N,lag_len))
history_y = np.zeros((N,lag_len))
trails = [plot(hx,hy)[0] for hx,hy in zip(history_x,history_y)]
def update_frame(i):
frame_num = i
newdatax = r[:,0] + random.rand(N)
newdatay = r[:,1] + random.rand(N)
line.set_ydata(newdatay)
line.set_xdata(newdatax)
history_x[:,frame_num%lag_len] = newdatax
history_y[:,frame_num%lag_len] = newdatay
for hx,hy,ln_h in zip(history_x,history_y,trails):
ln_h.set_xdata(hx)
ln_h.set_ydata(hy)
plt.title("At timestep: %d" %i)
plt.hold(True)
return (line,) + tuple(trails)
anim = animation.FuncAnimation(fig, update_frame,
frames=100, interval=20)
As for the boxes, use Rectangle ( Draw rectangle (add_patch) in pylab mode ), and the optional args to pass to FuncAnimation
.
This isn't perfect, there are some strange details of it looping back over it's self (frame 50 in one loop is not the same as frame 50 next time it passes over), there is a transient for the first 10 frames when there are a bunch of zeros in the history (you can fix that by initializing the history array to be 10 copies of the initial points)