Memory usage for matplotlib animation - python

I've been tweaking the code from this page http://jakevdp.github.io/blog/2012/08/18/matplotlib-animation-tutorial/ to make my own animation, but it crashes very quickly. Looking at the task manager, I can see that the memory build-up from running the program rises to 1gb within 30 seconds, which is very significant for my less-than-impressive laptop. From the way the code was calling animation(i) to set the y_data on the line every time, is the old data not replaced, causing the memory build-up? I'd like to fix this. My knowledge on the inner workings of matplotlib is limited, and some things I've tried is putting close(), clf(), and gc.collect() in animation(i), but none of them worked.
"""
Matplotlib Animation Example
author: Jake Vanderplas
email: vanderplas#astro.washington.edu
website: http://jakevdp.github.com
license: BSD
Please feel free to use and modify this, but keep the above information. Thanks!
"""
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
# initialization function: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation function. This is called sequentially
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True)
# save the animation as an mp4. This requires ffmpeg or mencoder to be
# installed. The extra_args ensure that the x264 codec is used, so that
# the video can be embedded in html5. You may need to adjust this for
# your system: for more information, see
# http://matplotlib.sourceforge.net/api/animation_api.html
# anim.save('basic_animation.mp4', fps=30, extra_args=['-vcodec', 'libx264'])
plt.show()

By default the animation code tries to save some number of frames (defaults to 100). Try explicitly setting this to zero:
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True,
save_count=0)

Related

Python matplotlib plot /graph partial refresh from starting point

Sorry I am a bit new to python and matplotlib so I dont know if I am asking it correctly. As of now I am plotting graphs where I collect an array of integers coming via serial port and refreshing the whole plot area at once. Now I want to do partial refresh (idk if it is the correct word) something like a PPG/ECG trace where once the line/trace reaches the end of plot area it starts from beginning, something like in the example here
[1]: http://theblogofpeterchen.blogspot.com/2015/02/html5-high-performance-real-time.html.
I do understand that if I keep on appending the serial port data and plotting it as soon as it arrives will keep on extending the plot forward but I have no clue how to return back at the the beginning point and redraw it gradually as in ECG.
Kindly help in this regard
Thank you
I have a solution below using FuncAnimation.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from scipy.misc import electrocardiogram
ecg = electrocardiogram()[0:1000]
fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], '-')
# this is repeat length
n = 200
def init():
ax.set_xlim(0, n)
ax.set_ylim(-1, 2)
return ln,
def update(i):
# update xlim of axes
if i % n == 0:
ln.axes.set_xlim(int(i/n)*n, int(i/n)*n+n)
else:
xdata.append(i)
ydata.append(ecg[i])
ln.set_data(xdata, ydata)
return ln,
ani = FuncAnimation(fig, update, frames=1000, init_func=init, blit=True, interval=10, repeat=False)

Matplotlib animation duration and why it won't stop

matplotlib animation duration explained that basically the argument franes in FuncAnimation defines the total amount of frames it should animate. However, when I run the example code it just seems to be running constantly. I expected the fig will stop updating after 4 seconds but it didnot. Is there some kind of loop I need to disable? Thanks. I ran it on Python 3.7 and matplotlib 3.0.3
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2,2))
line, = ax.plot([], [], lw=2)
# init func, plot the background of each frame.
def init():
line.set_data([], [])
return line,
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=True)
plt.show()
You need repeat=False in your FuncAnimation call.
Checkout the doc please https://matplotlib.org/api/_as_gen/matplotlib.animation.FuncAnimation.html#matplotlib.animation.FuncAnimation
repeat : bool, optional
Controls whether the animation should repeat when the sequence of frames is completed. Defaults to True.
As default it repeats animation but you can use
FuncAnimation(... , repeat=False)
Doc: FuncAniamtion

Drawing a Nyquist diagram animation on python

I am currently trying to create a python code that is supposed to draw an animated nyquist diagram and save it as a gif file.
The problem is, I don't know how to make the animate function work. Here is a code I found on the internet that works:
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line,
As you may know, linspace and sin are functions that returns arrays with the sequential values. The real and imag variables on my code are also arrays with sequential values. w variable is an array too, corresponding to the values of real and imag. I wanted real and imag to be drawn for every w value, thus being the "step" of the animation. What is wrong with my code?
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation as an
import control
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(-2, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
# initialization function: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation function. This is called sequentially
def animate(i):
G = control.TransferFunction((1),(1,0))
real, imag, w = control.nyquist(G)
line.set_data(real, imag)
return line,**
# call the animator. blit=True means only re-draw the parts that have changed.
anim = an.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=200, blit=True)
#anim.save('GIF.gif', dpi=100, writer='imagemagick')
plt.title('Nyquist Diagram of 1/s')
plt.ylabel('Imaginary')
plt.xlabel('Real')
plt.grid(True)
plt.show()
In your code you are always ploting the current data (real and imag), but according to matplotlib you need to use a list of data which is updated in every iteration.
Matplotlib - Animation
In the code below I have created the lists realData and imagData, so in every iteration real and imag are appended to the list and these lists are used as line.set_data arguments.
I have also used the control package just in the begining because it already returns a list containing everything you need to plot.
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation as an
import control
# First set up the figure, the axis, and the plot element we want to animate
fig, ax = plt.subplots()
realData, imagData = [], []
line, = plt.plot([], [], 'rx', animated=True)
G = control.TransferFunction((1),(1,0))
real, imag, w = control.nyquist(G)
print(real)
print(imag)
def init():
ax.set_xlim(-2, 2)
ax.set_ylim(-10, 10)
return line,
# animation function. This is called sequentially
def animate(i):
realData.append(real[i])
imagData.append(imag[i])
line.set_data(realData, imagData)
return line,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = an.FuncAnimation(fig, animate, init_func=init,
frames=range(len(real)), interval=2, blit=True)
#anim.save('GIF.gif', dpi=100, writer='imagemagick')
plt.title('Nyquist Diagram of 1/s')
plt.ylabel('Imaginary')
plt.xlabel('Real')
plt.grid(True)
plt.show()

Saving Animation with matplotlib?

I have installed ffmpeg using homebrew.
However the problem I am facing now is that no animation is saved when running the script.
I have included below my script and my .bash_profile
import matplotlib
matplotlib.use('TKAgg')
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
# initialization function: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation function. This is called sequentially
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True)
# save the animation as an mp4. This requires ffmpeg or mencoder to be
# installed. The extra_args ensure that the x264 codec is used, so that
# the video can be embedded in html5. You may need to adjust this for
# your system: for more information, see
# http://matplotlib.sourceforge.net/api/animation_api.html
anim.save('basic_animation.mp4', fps=30)
.bash_profile
export PATH=$PATH:/$HOME/../../usr/local/Celler/ffmpreg/2.2.2/bin
export FFMPEG_BIN=/$HOME/../../usr/local/Cellar/ffmpeg/2.2.2/bin/
I was able to get output the animation correctly by Using an ipython notebook with the Anaconda environment.
There was a bit of a work around needed to get the animation to be displayed in the ipython notebook. Here it is:
from matplotlib import animation
from tempfile import NamedTemporaryFile
VIDEO_TAG = """<video controls>
<source src="data:video/x-webm;base64,{0}" type="video/webm">
Your browser does not support the video tag.
</video>"""
def anim_to_html(anim):
if not hasattr(anim, '_encoded_video'):
with NamedTemporaryFile(suffix='.webm') as f:
anim.save(f.name, fps=6, extra_args=['-vcodec', 'libvpx'])
video = open(f.name, "rb").read()
anim._encoded_video = video.encode("base64")
return VIDEO_TAG.format(anim._encoded_video)
from IPython.display import HTML
def display_animation(anim):
plt.close(anim._fig)
return HTML(anim_to_html(anim))
Once the above code was in place, the following animation was output correctly into the ipython notebook:
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
# initialization function: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation function. This is called sequentially
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True)
anim.save('basic_animation.mp4', fps=30, extra_args=['-vcodec', 'libx264'])
display_animation(anim)
For some reason when I right click and save I am unable to view the movie in a readable format...if anyone knows or figures out the solution to this please let me know!

Matplotlib monitor - plot values from table every X seconds

I'm new to python and matplotlib and need a few pointers. I'm trying to write a monitor that queries a table and plots the results. from the table I can extract a timestamp I'd like to use for the X axis and a #of seconds I'd like to use for the Y value (number of packets sent). I'm not sure where "i" is populated for the animate function. My plot comes up but is empty. I'm not sure what ax.set_xlim should be set to and finally how do I get the date/timestamp to show up on the x-axis?
Im trying to modify the following example:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
ax = plt.axes(ylim=(0, 45))
line, = ax.plot([], [], lw=5)
def init():
line.set_data([], [])
return line,
def animate(i):
x,y,dk=getData()
line.set_data(x, y)
return line,
def Execute():
#anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=200, blit=True)
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=2000)
plt.show()
return(anim)
def getDataSql(sql):
... run sql
return(rl)
def getData():
...format return for getDataSql
...return X ex(2013-04-12 18:18:24) and Y ex(7.357) (both are lists)
return(X,Y,xy)
x=Execute()
def Execute():
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=2000, blit=True)
plt.show()
return anim
anim = Execute()
If you don't return the anim object (which has all the timers ect) in it, it gets garbage collected when Execute returns, which deletes all those objects, and hence your animation does not run.
You might also test using blit=False, it is a bit slower (which isn't an issue as you are updating ever 2s), but it is a bit less fincky to get working right.
Also try
ax.get_xaxis().set_major_locator(matplotlib.dates.AutoDateLocator())
ax.get_xaxis().set_major_formatter(matplotlib.dates.AutoDateFormatter())
before you run anything.

Categories

Resources