animate with variable time - python

I have trajectory data where each vehicle has its own time to start. Each vehicle is a point in the animation. So, in the dataset, for each row there is coordinate point (x,y) along with a timestamp. So, fixed time interval would not work for me. I tried with loop and sleep but it not showing the animation but only the first result. But if debug line by line, it seems okay(updating with new points after each iteration). Here is my code (this is to test: loop, sleep and animation):
#sample data
x=[20,23,25,27,29,31]
y=[10,12,14,16,17,19]
t=[2,5,1,4,3,1,]
#code
fig, ax = plt.subplots()
ax.set(xlim=(10, 90), ylim=(0, 60))
for i in range(1,6):
ax.scatter(x[:i+1], y[:i+1])
plt.show()
time.sleep(t[i])
How can get the animation effect?

The already mentioned FuncAnimation has a parameter frame that the animation function can use an index:
import matplotlib.pyplot as plt
import matplotlib.animation as anim
fig = plt.figure()
x=[20,23,25,27,29,31]
y=[10,12,14,16,17,19]
t=[2,9,1,4,3,9]
#create index list for frames, i.e. how many cycles each frame will be displayed
frame_t = []
for i, item in enumerate(t):
frame_t.extend([i] * item)
def init():
fig.clear()
#animation function
def animate(i):
#prevent autoscaling of figure
plt.xlim(15, 35)
plt.ylim( 5, 25)
#set new point
plt.scatter(x[i], y[i], c = "b")
#animate scatter plot
ani = anim.FuncAnimation(fig, animate, init_func = init,
frames = frame_t, interval = 100, repeat = True)
plt.show()
Equivalently, you could store the same frame several time in the ArtistAnimation list. Basically the flipbook approach.
Sample output:

Related

Generating figures in a loop and creating animation

I'm doing a complicated calculation inside a while loop in Python, and plotting the results for each iteration in a figure. I'm having problems saving each figure and making a gif with these images. I tried the suggestions in this post, but I don't know what to put in the imshow field:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
thist = 4 # total time
tstep = 1 # time step
# ims is a list of lists, each row is a list of artists to draw in the
# current frame; here we are just animating one artist, the image, in
# each frame
ims = []
while thist>=tstep:
x = np.linspace(0,2,100)
y = np.sin(x*(thist-tstep)) # complicated calculation
fig = plt.figure(figsize=(10,6))
ax = plt.subplot(111)
plt.plot(x,y)
#plt.show()
im = plt.imshow(fig)
ims.append([im])
tstep += 1
ani = animation.ArtistAnimation(fig,ims,interval=100,blit=True,repeat_delay=1000)
ani.save('mytest.gif', writer='imagemagick')

Animating a Scatter Plot with Respect to Time

I currently have an array G = [x,y,t] where each spatial point (G[0][i], G[1][i]) has a time component t = G[2][i]. The array is sorted by time. I am trying to animate the scatter plot so points show up in chronological order and do not disappear. Here is my current code:
from matplotlib.animation import FuncAnimation
import matplotlib.animation as animation
fig = plt.figure(figsize=(10,7))
ax = plt.subplot(111, xlim=(0,1), ylim=(0,1))
def animationUpdate(k):
x = G[0][:k]
y = G[1][:k]
scat.set_offsets(np.c_[x,y])
return scat
anim = FuncAnimation(fig, animationUpdate, frames=10, interval=100, blit=True)
I get the error "'PathCollection' object is not iterable" which I am not sure how to fix. I am also unsure how to arrange it so the points show up with respect to their time component. Do I modify the frames or interval section of FuncAnimation? Thanks!

Blit Behaviour in FuncAnimate -Want to keep previous data

I'm trying to animate a figure using matplotlib->FuncAnimate function. However, I'm having trouble understanding how Blit works. With each frame, I want to draw only the new data point on top of the old one. It says that using Blit it should automatically update only the values that changed. Thus, if I turn it on (blit=True) the previous data points should remain in my figure. But this is not the case. The previous data get deleted and the figure gets redraw from scratch.
In the documentation, it says that I have to return "iterable_of_artists" and the algorithm will know which data has changed. I want to just pass the new data and just plot on top of the old one. By the way, what is an "iterable_of_artists", is that just a list of objects that can be drawn? if someone could point me out to the definition, I would appreciate it.
Anyway, I have worked several base examples that show the odd behavior. In the first example, I'm turning Blit=True and drawing only the new data using the animate function. This in theory should draw on top of the old ones, but is not the case, only the new data is drawn.
import time
import random
import numpy
import matplotlib
import matplotlib.pyplot as pyplot
from matplotlib.animation import FuncAnimation
def livePlot():
fig, ax = pyplot.subplots(1,1)
ax = pyplot.axes(xlim=(0, 2), ylim=(0, 100))
line, = ax.plot([], [], 'ro') #ax.plot will return a tupple
def init():
line.set_data(0, 50)
return line, #Return is not necessary when blit=False
def animate(frame):
x = frame
y = random.randint(0, 100)
line.set_data(x,y)
return line, #Return is not necessary when blit=False
animation = FuncAnimation(
fig, animate,
init_func = init,
frames= [0.5, 1, 1.5, 2.0],
interval=1000,
repeat=False,
blit=True, # Turning on Blit
cache_frame_data = True)
pyplot.show()
if __name__ == "__main__":
livePlot()
I was able to achieve my goal by tricking the FuncAnimate method. I can use the ax and plot in each frame the new data. If I do that, the old data remains and only the new data is drawn. However, I can do that with Blit=True or Blit=False, it has no effect. So, I'm so confused on how Blit works and what would be the correct way to plot only the new data without having to create a list with all the data to plot. Passing a large list will create a large variable in memory if I have a long set of data points. Here is my workaround but I'm not sure if this is the correct way to do it or if there is a better ways of using Blit=True and just redraw the new data.
import time
import random
import numpy
import matplotlib
import matplotlib.pyplot as pyplot
from matplotlib.animation import FuncAnimation
def livePlot():
fig, ax = pyplot.subplots(1,1)
ax = pyplot.axes(xlim=(0, 2), ylim=(0, 100))
def init():
ax.plot(0, 50, 'ro')
return []
def animate(frame):
x = frame
y = random.randint(0, 100)
ax.plot(x, y, 'ro') # plotting directly on the axis. This keeps the old data
return [] # fooling the blit algorithm with an empty stream
animation = FuncAnimation(
fig, animate,
init_func = init,
frames= [0.5, 1, 1.5, 2.0],
interval=1000,
repeat=False,
blit=True,
cache_frame_data = True)
pyplot.show()
if __name__ == "__main__":
livePlot()

Smooth animations with matplotlib

Yesterday I started my journey into learning how to animate functions to do some small projects for my work. Right now, I'm trying to code a simple linear equation graph that only shows a dot at a time
from itertools import count
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
plt.style.use('seaborn-paper')
x_vals = []
y_vals = []
index = count()
def animate(i):
x_vals = []
y_vals = []
x_vals*= 0
y_vals*= 0
var=next(index)
x_vals.append(var*0.05 % 10)
y_vals.append(var*0.05 % 10)
plt.cla()
plt.xlim(0,10)
plt.ylim(0,10)
plt.scatter(x_vals,y_vals)
ani = FuncAnimation(plt.gcf(), animate, interval=1)
plt.tight_layout()
plt.show()
Keep in mind that this is a super sketchy solution for what I'm trying to do.
My question is: is there a way to smooth my dot animation so it doesnt look choppy?
I found a way to simplify your code which could help make it faster. Passing index as the function for the frames argument definitely increased the speed.
index = count()
def animate(i):
var = next(index)
v = var*0.05 % 10
plt.cla()
plt.xlim(0,10)
plt.ylim(0,10)
plt.scatter(v,v)
ani = FuncAnimation(plt.gcf(), animate, frames = index, interval = 1)
plt.tight_layout()
plt.show()
If you look at this post you will see (a) smooth animations, and (b) the author's use of optional arguments to FuncAnimation.

Multi body animation in python returns static picture

Here is a program that I have written to do an animation in matplotlib. The program concerns a system of 18 particles arranged initially in a hexagonal lattice. The initial configuration is given under the definition of simPoints(simData).
The system is evolved over time according to the rule x[i]=x[i]+L/2.0, in both x and y direction. Particles going out of the window are brought in through the other side. These updates are mentioned under the function simData().
But all I get out of this code is a static picture of the initial configuration of particles.
from numpy import*
import matplotlib.pyplot as plt
import matplotlib.animation as animation
L=1 # lattice constant = sigma*2**0.5 (Let)
x=zeros(18,float)
y=zeros(18,float)
#~~~~~~~~~~~~~~~~~ ANIMATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def simData():
t = 1
while t<=20:
for i in range(18):
x[i]=x[i]+L/2.0
y[i]=y[i]+L/2.0
if x[i]>L*3: # translate back the particle if it goes out of window limit 0 to L*cell
x[i]=x[i]-L*3
elif x[i]<0:
x[i]=L*3-x[i]
if y[i]>L*3: # translate back the particle if it goes out of window limit 0 to L*cell
y[i]=y[i]-L*3
elif y[i]<0:
y[i]=L*3-y[i]
t=t+1
yield x, y
def simPoints(simData):
k=0
for i in range(0,6,1):
for j in range(0,6,1):
if (i+j)%2==0:
x[k]=i*L*.5+.25*L
y[k]=j*L*.5+.25*L
k=k+1
line.set_data(x, y)
return line,
fig = plt.figure()
ax = fig.add_subplot(111)
line, = ax.plot(x, y,'bo', ms=8)
ax.set_ylim(0, L*3)
ax.set_xlim(0, L*3)
ani = animation.FuncAnimation(fig, simPoints, simData, blit=False, interval=100)
plt.show()
How can I animate the lattice? I have a feeling that the argument interval=100 is not used wisely.
I've made some minor changes in Your code, as You can see below. It's animating now, however the simPoints() is commented out. The major issue is that if You initialize the points like that, after each step they end up in the same places. Dots move, but another dots take their places, so it looks like the plot isn't moving. You may want to change the simData() function, for example make the changes more subtle or random, to avoid that case.
from numpy import*
import matplotlib.pyplot as plt
import matplotlib.animation as animation
L=1 # lattice constant = sigma*2**0.5 (Let)
x=array([0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.1,0.11,0.12,0.13,0.14,0.15,0.16,0.17,0.18])
#x=zeros(18,float)
y=zeros(18,float)
#~~~~~~~~~~~~~~~~~ ANIMATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def simData():
t = 1
while t<=20:
for i in range(18):
x[i]=x[i]+L/2.0
y[i]=y[i]+L/2.0
if x[i]>L*3: # translate back the particle if it goes out of window limit 0 to L*cell
x[i]=x[i]-L*3
elif x[i]<0:
x[i]=L*3-x[i]
if y[i]>L*3: # translate back the particle if it goes out of window limit 0 to L*cell
y[i]=y[i]-L*3
elif y[i]<0:
y[i]=L*3-y[i]
t=t+1
def simPoints():
k=0
for i in range(0,6,1):
for j in range(0,6,1):
if (i+j)%2==0:
x[k]=i*L*.5+.25*L
y[k]=j*L*.5+.25*L
k=k+1
fig = plt.figure()
ax = plt.axes()
#simPoints()
line, = ax.plot(x, y,'bo', ms=8)
ax.set_ylim(0, L*3)
ax.set_xlim(0, L*3)
def animate(i):
simData()
print x
line.set_data(x, y)
return line,
ani = animation.FuncAnimation(fig, animate, blit=False, interval=100, frames=200)
plt.show()
The animation is all right and works. Your Problem is the symmetry in your logic. To test the animation just add some random value:
def simPoints(simData):
k=0
for i in range(0,6,1):
for j in range(0,6,1):
if (i+j)%2==0:
# just add some randomness to see the random x-movement
x[k]=i*L*.5+.25*L + random.random(1)
y[k]=j*L*.5+.25*L
k=k+1
line.set_data(x, y)
return line,
Every point xy you calculate is occupied beforehand by an other. Thus it seems static. If you want to see the in-between steps you need to update your data generation (esp. get rid of the modulus). Or expand the boundaries/graph-limits, so you can see the dots move.

Categories

Resources