How to draw figure and animate it in IPython

blog post: http://yuntan-t.hateblo.jp/entry/2015/06/22/143826

License: BSD (C) 2015, Yuto Tokunaga. Feel free to use, distribute, and modify with the above attribution.

In [1]:
%matplotlib inline
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt

To draw figure, use Pillow (PIL).

In [2]:
from PIL import Image, ImageDraw
In [3]:
w,h=600,600 # width and height
img = Image.new('RGB', (w,h), '#fff') # create image filled with white color
draw = ImageDraw.Draw(img) # get draw object
In [4]:
# draw crossover line
draw.line((0,h/2,w,h/2), fill='#333', width=2)
draw.line((w/2,0,w/2,h), fill='#333', width=2)
plt.imshow(img) # ok, let's show image
Out[4]:
<matplotlib.image.AxesImage at 0x7fb8a246f6d8>
In [5]:
# draw a circle in center
draw.ellipse((250,250,350,350), fill='#00f')
plt.imshow(img)
Out[5]:
<matplotlib.image.AxesImage at 0x7fb8a2235710>

Next, animate it. You can use wonderfull method to embed matplotlib animation on http://jakevdp.github.io/blog/2013/05/12/embedding-matplotlib-animations/ (very thank you jakevdp!). So let's copy and paste and change a bit...

License: BSD (C) 2013, Jake Vanderplas. Feel free to use, distribute, and modify with the above attribution.

In [6]:
from tempfile import NamedTemporaryFile
import base64
from matplotlib import animation

VIDEO_TAG = """<video controls>
 <source src="data:video/x-m4v;base64,{0}" type="video/mp4">
 Your browser does not support the video tag.
</video>"""

def anim_to_html(anim):
    if not hasattr(anim, '_encoded_video'):
        with NamedTemporaryFile(suffix='.mp4') as f:
            anim.save(f.name, fps=20, extra_args=['-vcodec', 'libx264'])
            video = open(f.name, "rb").read()
        anim._encoded_video = base64.b64encode(video)
    
    return VIDEO_TAG.format(anim._encoded_video.decode())

animation.Animation._repr_html_ = anim_to_html
In [11]:
img_empty = Image.new('RGB', (w,h), '#fff') # empty image to clear figure

fig = plt.figure()
ax = plt.axes(xlim=(0, w), ylim=(h, 0)) # specify image size
aximg = ax.imshow(img_empty) # get AxisImage Object

# initialization function: draw the background of each frame
def init():
    aximg.set_data(img_empty)

# animation function.  This is called sequentially
def animate(i):
    img = img_empty.copy()
    draw = ImageDraw.Draw(img)
    
    # draw something you like
    t = i*10 if i*10 < 500 else 1000 - i*10
    draw.ellipse((t,t,100+t,100+t), fill='#2f2')
    
    aximg.set_data(img)
In [12]:
# it takes several seconds...
animation.FuncAnimation(fig, animate, init_func=init, frames=100, interval=20, blit=False)
Out[12]: