Time lapse animation - animation

I'm new to python, matplotlib, and animation.
I've not been able to find a clear, detailed description of
animation.FuncAnimation(, , , , , , ......), so I've been trying to modifiy examples I've found. What are all the allowed parameters for FuncAnimation in English?
I want to produce a graph of dots shown one at a time with a time about 1 second between appearances.
Here's my current code that just produces a continuous curve after a delay:
def init():
line1.set_data([],[],'og')
return line1,
def animate(x):
x = np.linspace(0, 650, num=20, endpoint = True) #start at 0, stop at 650, number of values
y1 = (v0_y/v0_x)*x - (g/2)*(x/v0_x)**2
line1.set_data(x, y1)
time.sleep(1)
return line1,
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=100, interval=3000, blit=True)
All suggestions appreciated!

You can check the documentation of FuncAnimation here, and this is an example code that does what you want:
from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np
xs = np.linspace(0, 650, num=20, endpoint = True)
ys = np.random.rand(20)
fig = plt.figure()
line1, = plt.plot([],[],'og')
plt.gca().set_xlim(0,650)
def init():
return line1,
def animate(i):
line1.set_data(xs[:i], ys[:i])
return line1,
anim = animation.FuncAnimation(fig, animate, init_func=init, interval=1000, blit=True)
plt.show()
Output window:

Related

how can I keep the last frame when I use matplotlib animation function with blit = True

I have to set blit = true, since the plotting is much faster. But after animation (repeat = false), if I use zoom in the figure, the figure will just disappear. I need to keep the last frame so that I can zoom in the last figure.
Thanks!
One work around is to initialize the animation using the last frame. The obvious down side is you have to precompute the last frame. Adapting this example would be
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
x = np.arange(0, 2*np.pi, 0.01)
line, = ax.plot(x, np.sin(x))
cnt = 50 # Define so we know what the last frame will be.
def init():
# Note the function is the same as `animate` with `i` set to the last value
line.set_ydata(np.sin(x + cnt / 100))
return line,
def animate(i):
line.set_ydata(np.sin(x + i / 100)) # update the data.
return line,
ani = animation.FuncAnimation(
fig, animate, init_func=init, interval=2, blit=True, save_count=cnt)
ani.save("mwe.mov")
fig.savefig("mwe.png")

Matplotlib: Animate function output in steps

I have a function that outputs return (x, y) and i would like to animate the x,y pair, from beginning to end. E.g. such that the line 'develops over time'.
This is what my output looks like:
x, y = stephan()
plt.plot(x,y)
And when I try to use a snippit of animation code:
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [])
def init():
line.set_data([], [])
return line,
def animate(i):
x, y = stephan()
line.set_data(x, y[i])
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20, blit=True)
I get this quite boring output:
It is plotting something, but certainly not the x,y output. I think that I might be using the animate or init function wrongly? And strangely enough, I haven't been able to find any code that does this quite simply.
If the call to stephan returns two floats, y[i] does not make any sense. Furthermore you would want to store the output in a list, to obtain a line and not a single dot per frame.
A working example could look like this
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
class Stephan():
i=0
def __call__(self):
self.i += 0.02
return self.i, np.random.randn(1)
stephan = Stephan()
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [])
def init():
line.set_data([], [])
return line,
X = []
def animate(i):
x, y = stephan()
X.append((x,y))
line.set_data(zip(*X))
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20, blit=True)
plt.show()
Alternatively, if stephan returns two lists of values, you could directly set those lists as data to the line.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
class Stephan():
x=[0]
y=[1]
def __call__(self):
self.x.append(self.x[-1]+0.02)
self.y.append(np.random.randn(1))
return self.x, self.y
stephan = Stephan()
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [])
def init():
line.set_data([], [])
return line,
def animate(i):
x, y = stephan()
line.set_data(x,y)
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20, blit=True)
plt.show()

Dynamic plot in python

I'm trying to create a plot in Python where the data that is being plotted gets updated as my simulation progresses. In MATLAB, I could do this with the following code:
t = linspace(0, 1, 100);
figure
for i = 1:100
x = cos(2*pi*i*t);
plot(x)
drawnow
end
I'm trying to use matplotlib's FuncAnimation function in the animation module to do this inside a class. It calls a function plot_voltage which recalculates voltage after each timestep in my simulation. I have it set up as follows:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def __init__(self):
ani = animation.FuncAnimation(plt.figure(2), self.plot_voltage)
plt.draw()
def plot_voltage(self, *args):
voltages = np.zeros(100)
voltages[:] = np.nan
# some code to calculate voltage
ax1 = plt.figure(2).gca()
ax1.clear()
ax1.plot(np.arange(0, len(voltages), 1), voltages, 'ko-')`
When my simulation runs, the figures show up but just freeze. The code runs without error, however. Could someone please let me know what I am missing?
Here is a translation of the matlab code into matplotlib using FuncAnimation:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
t = np.linspace(0, 1, 100)
fig = plt.figure()
line, = plt.plot([],[])
def update(i):
x = np.cos(2*np.pi*i*t)
line.set_data(t,x)
ani = animation.FuncAnimation(fig, update,
frames=np.linspace(1,100,100), interval=100)
plt.xlim(0,1)
plt.ylim(-1,1)
plt.show()

How do I plot two animations in a single plot with matplotlib?

In the following code I have two separate animations and I have plotted them in a two separate subplots. I want both of them to run in a single plot instead of this. I have tried the approach explained below but it is giving me issues as explained below. Please help
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time as t
x = np.linspace(0,5,100)
fig = plt.figure()
p1 = fig.add_subplot(2,1,1)
p2 = fig.add_subplot(2,1,2)
def gen1():
i = 0.5
while(True):
yield i
i += 0.1
def gen2():
j = 0
while(True):
yield j
j += 1
def run1(c):
p1.clear()
p1.set_xlim([0,15])
p1.set_ylim([0,100])
y = c*x
p1.plot(x,y,'b')
def run2(c):
p2.clear()
p2.set_xlim([0,15])
p2.set_ylim([0,100])
y = c*x
p2.plot(x,y,'r')
ani1 = animation.FuncAnimation(fig,run1,gen1,interval=1)
ani2 = animation.FuncAnimation(fig,run2,gen2,interval=1)
fig.show()
I tried creating a single subplot instead of p1 and p2 and have both the plots graphed in that single subplot. That is just plotting one graph and not both of them. As far as I can say it is because one of them is getting cleared right after it is plotted.
How do I get around this problem?
As you do not show the code that is actually producing the problem, it's hard to tell where the problem lies.
But to answer the question of how to animate two lines in the same axes (subplot), we can just get rid of the clear() command and update the lines, instead of producing a new plot for every frame (which is more efficient anyways).
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
x = np.linspace(0,15,100)
fig = plt.figure()
p1 = fig.add_subplot(111)
p1.set_xlim([0,15])
p1.set_ylim([0,100])
# set up empty lines to be updates later on
l1, = p1.plot([],[],'b')
l2, = p1.plot([],[],'r')
def gen1():
i = 0.5
while(True):
yield i
i += 0.1
def gen2():
j = 0
while(True):
yield j
j += 1
def run1(c):
y = c*x
l1.set_data(x,y)
def run2(c):
y = c*x
l2.set_data(x,y)
ani1 = animation.FuncAnimation(fig,run1,gen1,interval=1)
ani2 = animation.FuncAnimation(fig,run2,gen2,interval=1)
plt.show()

Animate like Google Finance charts in Matplotlib?

I just started toying around with Matplotlib's Animation capabilities in order to produce a Google Finance looking chart.
I combined two examples I found on the project website (Draggable rectangle exercise, api example code: date_demo.py) and tweaked them a bit to come up with the code listed at the bottom.
While it doesn't look too bad, I would like the top chart (master) update dynamically as the bottom chart (slave) selection is moved around, and not only when the bottom selection is released. How can I do this? I tried to move the self.rect.figure.canvas.draw() bit to the on_motion method, but it seems to interfere with the blit stuff as the bottom selection won't render properly.
So I would assume the solution would be to do the intelligent animation for the bottom chart, i.e., the blit-ing bit, while the top chart is just re-drawn altogether. The issue is that the only way I can redraw anything is through the re-drawing the whole canvas, and this would include the bottom chart. I did find the draw() method for matplotlib.axes, but I can't get it to work. As I said above, preferably I would like to just re-draw the top chart while the bottom one is blit-ed the clever way. Does anyone know how to do this?
Here is my code so far. Please excuse the code, it's a bit untidy.
import datetime
import numpy as np
import sys
import time
import wx
import matplotlib
from matplotlib.figure import Figure
import matplotlib.dates as mdates
import matplotlib.ticker as mtickers
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
import matplotlib.patches as mpatches
class DraggableRectangle:
lock = None
def __init__(self, rect, master, xMin, xMax):
self.rect = rect
self.press = None
self.background = None
self.xMax = xMax
self.xMin = xMin
self.master = master
def connect(self):
self.cidpress = self.rect.figure.canvas.mpl_connect('button_press_event', self.on_press)
self.cidrelease = self.rect.figure.canvas.mpl_connect('button_release_event', self.on_release)
self.cidmotion = self.rect.figure.canvas.mpl_connect('motion_notify_event', self.on_motion)
def on_press(self, event):
if event.inaxes != self.rect.axes: return
if DraggableRectangle.lock is not None: return
contains, attrd = self.rect.contains(event)
if not contains: return
x0, y0 = self.rect.xy
self.press = x0, y0, event.xdata, event.ydata
DraggableRectangle.lock = self
canvas = self.rect.figure.canvas
axes = self.rect.axes
self.rect.set_animated(True)
canvas.draw()
self.background = canvas.copy_from_bbox(self.rect.axes.bbox)
axes.draw_artist(self.rect)
canvas.blit(axes.bbox)
def on_motion(self, event):
if DraggableRectangle.lock is not self: return
if event.inaxes != self.rect.axes: return
x0, y0, xpress, ypress = self.press
dx = event.xdata - xpress
dy = 0
if x0+dx > self.xMax:
self.rect.set_x(self.xMax)
elif x0+dx < self.xMin:
self.rect.set_x(self.xMin)
else:
self.rect.set_x(x0+dx)
self.rect.set_y(y0+dy)
canvas = self.rect.figure.canvas
axes = self.rect.axes
canvas.restore_region(self.background)
self.master.set_xlim(self.rect.get_x(), self.rect.get_x() + 92)
axes.draw_artist(self.rect)
canvas.blit(axes.bbox)
def on_release(self, event):
if DraggableRectangle.lock is not self: return
self.press = None
DraggableRectangle.lock = None
self.rect.set_animated(False)
self.background = None
self.rect.figure.canvas.draw()
def disconnect(self):
self.rect.figure.canvas.mpl_disconnect(self.cidpress)
self.rect.figure.canvas.mpl_disconnect(self.cidrelease)
self.rect.figure.canvas.mpl_disconnect(self.cidmotion)
class MplCanvasFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, title='First Chart', size=(800, 700))
datafile = matplotlib.get_example_data('goog.npy')
r = np.load(datafile).view(np.recarray)
datesFloat = matplotlib.dates.date2num(r.date)
figure = Figure()
xMaxDatetime = r.date[len(r.date)-1]
xMinDatetime = r.date[0]
xMaxFloat = datesFloat[len(datesFloat)-1]
xMinFloat = datesFloat[0]
yMin = min(r.adj_close) // 5 * 5
yMax = (1 + max(r.adj_close) // 5) * 5
master = figure.add_subplot(211)
master.plot(datesFloat, r.adj_close)
master.xaxis.set_minor_locator(mdates.MonthLocator())
master.xaxis.set_major_locator(mdates.MonthLocator(bymonth=(1,4,7,10)))
master.xaxis.set_major_formatter(mdates.DateFormatter('%b-%y'))
master.set_xlim(datesFloat[120], datesFloat[120]+92)
master.yaxis.set_minor_locator(mtickers.MultipleLocator(50))
master.yaxis.set_major_locator(mtickers.MultipleLocator(100))
master.set_ylim(yMin, yMax)
master.set_position([0.05,0.20,0.92,0.75])
master.xaxis.grid(True, which='minor')
master.yaxis.grid(True, which='minor')
slave = figure.add_subplot(212, yticks=[])
slave.plot(datesFloat, r.adj_close)
slave.xaxis.set_minor_locator(mdates.MonthLocator())
slave.xaxis.set_major_locator(mdates.YearLocator())
slave.xaxis.set_major_formatter(mdates.DateFormatter('%b-%y'))
slave.set_xlim(xMinDatetime, xMaxDatetime)
slave.set_ylim(yMin, yMax)
slave.set_position([0.05,0.05,0.92,0.10])
rectangle = mpatches.Rectangle((datesFloat[120], yMin), 92, yMax-yMin, facecolor='yellow', alpha = 0.4)
slave.add_patch(rectangle)
canvas = FigureCanvas(self, -1, figure)
drag = DraggableRectangle(rectangle, master, xMinFloat, xMaxFloat - 92)
drag.connect()
app = wx.PySimpleApp()
frame = MplCanvasFrame()
frame.Show(True)
app.MainLoop()
I had a chance to work on this this morning (we are having a 2nd blizzard for the last 3 days). You are right, if you try to redraw the entire figure in the on_motion, it messes up the animation of the yellow rectangle. The key is to also blit the line on the master sub plot.
Try this code out:
import datetime
import numpy as np
import sys
import time
import wx
import matplotlib
from matplotlib.figure import Figure
import matplotlib.dates as mdates
import matplotlib.ticker as mtickers
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
import matplotlib.patches as mpatches
class DraggableRectangle:
lock = None
def __init__(self, rect, master, xMin, xMax):
self.rect = rect
self.press = None
self.slave_background = None
self.master_background = None
self.xMax = xMax
self.xMin = xMin
self.master = master
self.master_line, = self.master.get_lines()
def connect(self):
self.cidpress = self.rect.figure.canvas.mpl_connect('button_press_event', self.on_press)
self.cidrelease = self.rect.figure.canvas.mpl_connect('button_release_event', self.on_release)
self.cidmotion = self.rect.figure.canvas.mpl_connect('motion_notify_event', self.on_motion)
def on_press(self, event):
if event.inaxes != self.rect.axes: return
if DraggableRectangle.lock is not None: return
contains, attrd = self.rect.contains(event)
if not contains: return
x0, y0 = self.rect.xy
self.press = x0, y0, event.xdata, event.ydata
DraggableRectangle.lock = self
canvas = self.rect.figure.canvas
axes = self.rect.axes
# set up our animated elements
self.rect.set_animated(True)
self.master_line.set_animated(True)
self.master.xaxis.set_visible(False) #we are not animating this
canvas.draw()
# backgrounds for restoring on animation
self.slave_background = canvas.copy_from_bbox(self.rect.axes.bbox)
self.master_background = canvas.copy_from_bbox(self.master.axes.bbox)
axes.draw_artist(self.rect)
canvas.blit(axes.bbox)
def on_motion(self, event):
if DraggableRectangle.lock is not self: return
if event.inaxes != self.rect.axes: return
x0, y0, xpress, ypress = self.press
dx = event.xdata - xpress
dy = 0
if x0+dx > self.xMax:
self.rect.set_x(self.xMax)
elif x0+dx < self.xMin:
self.rect.set_x(self.xMin)
else:
self.rect.set_x(x0+dx)
self.rect.set_y(y0+dy)
canvas = self.rect.figure.canvas
axes = self.rect.axes
# restore backgrounds
canvas.restore_region(self.slave_background)
canvas.restore_region(self.master_background)
# set our limits for animated line
self.master.set_xlim(self.rect.get_x(), self.rect.get_x() + 92)
# draw yellow box
axes.draw_artist(self.rect)
canvas.blit(axes.bbox)
#draw line
self.master.axes.draw_artist(self.master_line)
canvas.blit(self.master.axes.bbox)
def on_release(self, event):
if DraggableRectangle.lock is not self: return
self.press = None
DraggableRectangle.lock = None
# unanimate rect and lines
self.rect.set_animated(False)
self.master_line.set_animated(False)
self.slave_background = None
self.master_background = None
# redraw whole figure
self.master.xaxis.set_visible(True)
self.rect.figure.canvas.draw()
def disconnect(self):
self.rect.figure.canvas.mpl_disconnect(self.cidpress)
self.rect.figure.canvas.mpl_disconnect(self.cidrelease)
self.rect.figure.canvas.mpl_disconnect(self.cidmotion)
class MplCanvasFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, title='First Chart', size=(800, 700))
datafile = matplotlib.get_example_data('goog.npy')
r = np.load(datafile).view(np.recarray)
datesFloat = matplotlib.dates.date2num(r.date)
figure = Figure()
xMaxDatetime = r.date[len(r.date)-1]
xMinDatetime = r.date[0]
xMaxFloat = datesFloat[len(datesFloat)-1]
xMinFloat = datesFloat[0]
yMin = min(r.adj_close) // 5 * 5
yMax = (1 + max(r.adj_close) // 5) * 5
master = figure.add_subplot(211)
master.plot(datesFloat, r.adj_close)
master.xaxis.set_minor_locator(mdates.MonthLocator())
master.xaxis.set_major_locator(mdates.MonthLocator(bymonth=(1,4,7,10)))
master.xaxis.set_major_formatter(mdates.DateFormatter('%b-%y'))
master.set_xlim(datesFloat[120], datesFloat[120]+92)
master.yaxis.set_minor_locator(mtickers.MultipleLocator(50))
master.yaxis.set_major_locator(mtickers.MultipleLocator(100))
master.set_ylim(yMin, yMax)
master.set_position([0.05,0.20,0.92,0.75])
master.xaxis.grid(True, which='minor')
master.yaxis.grid(True, which='minor')
slave = figure.add_subplot(212, yticks=[])
slave.plot(datesFloat, r.adj_close)
slave.xaxis.set_minor_locator(mdates.MonthLocator())
slave.xaxis.set_major_locator(mdates.YearLocator())
slave.xaxis.set_major_formatter(mdates.DateFormatter('%b-%y'))
slave.set_xlim(xMinDatetime, xMaxDatetime)
slave.set_ylim(yMin, yMax)
slave.set_position([0.05,0.05,0.92,0.10])
rectangle = mpatches.Rectangle((datesFloat[120], yMin), 92, yMax-yMin, facecolor='yellow', alpha = 0.4)
slave.add_patch(rectangle)
canvas = FigureCanvas(self, -1, figure)
drag = DraggableRectangle(rectangle, master, xMinFloat, xMaxFloat - 92)
drag.connect()
app = wx.PySimpleApp()
frame = MplCanvasFrame()
frame.Show(True)
app.MainLoop()

Resources