elastic-grids-of-edges

Dans un notebook précédent, on a vu comment créer une grille hexagonale et comment l'animer.

On va maintenant utiliser MoviePy pour animer ces plots.

In [1]:
%load_ext autoreload
%autoreload 2
In [2]:
from elasticite import EdgeGrid
e = EdgeGrid()

Cette librairie permet de faire des animations depuis diverses librairies de visualisation, comme:

In [3]:
import os
name = 'sinc_vispy'
fps = 25
if not os.path.isfile(os.path.join('../files/2015-10-14_elasticite/', name + '.mp4')):
    from moviepy.editor import VideoClip
    import numpy as np
    from vispy import app, scene
    app.use_app('pyglet')
    from vispy.gloo.util import _screenshot

    canvas = scene.SceneCanvas(keys='interactive')
    view = canvas.central_widget.add_view()
    xx, yy = np.arange(-1,1,.02),np.arange(-1,1,.02)
    X,Y = np.meshgrid(xx,yy)
    R = np.sqrt(X**2+Y**2)
    Z = lambda t : 0.1*np.sin(10*R-2*np.pi*t)
    surface = scene.visuals.SurfacePlot(x= xx-0.1, y=yy+0.2, z= Z(0),
                            shading='smooth', color=(0.5, 0.5, 1, 1))
    view.add(surface)

    # Use a 3D camera
    # Manual bounds; Mesh visual does not provide bounds yet
    # Note how you can set bounds before assigning the camera to the viewbox
    cam = scene.TurntableCamera(elevation=30, azimuth=30, up='z', distance=2)
    view.camera = cam

    canvas.show()

    # ANIMATE WITH MOVIEPY
    def make_frame(t):
        surface.set_data(z = Z(t)) # Update the mathematical surface
        canvas.on_draw(None) # Update the image on Vispy's canvas
        return _screenshot((0,0,canvas.size[0],canvas.size[1]))[:,:,:3]

    animation = VideoClip(make_frame, duration=1).resize(width=350)
    animation.write_videofile('../files/2015-10-14_elasticite/' + name + '.mp4', fps=fps)
e.ipython_display(name)

Mais ce qui nous intéresse c'est de convertir nos trames construites avec matplotlib:

In [4]:
name = 'sinc_mpl' 
if not os.path.isfile(os.path.join('../files/2015-10-14_elasticite/', name + '.mp4')):
    import matplotlib.pyplot as plt
    import numpy as np
    from moviepy.video.io.bindings import mplfig_to_npimage
    import moviepy.editor as mpy

    # DRAW A FIGURE WITH MATPLOTLIB
    duration = 2.

    fig_mpl, ax = plt.subplots(1,figsize=(5,3), facecolor='white')
    xx = np.linspace(-2,2,200) # the x vector
    zz = lambda d: np.sinc(xx**2)+np.sin(xx+d) # the (changing) z vector
    ax.set_title("Elevation in y=0")
    ax.set_ylim(-1.5,2.5)
    line, = ax.plot(xx, zz(0), lw=3)

    # ANIMATE WITH MOVIEPY (UPDATE THE CURVE FOR EACH t). MAKE A GIF.

    def make_frame_mpl(t):
        line.set_ydata( zz(2*np.pi*t/duration))  # <= Update the curve
        return mplfig_to_npimage(fig_mpl) # RGB image of the figure

    animation = mpy.VideoClip(make_frame_mpl, duration=duration)
    animation.write_videofile('../files/2015-10-14_elasticite/' + name + '.mp4', fps=fps)
e.ipython_display(name)
In [5]:
name = 'circle'
if not os.path.isfile(os.path.join('../files/2015-10-14_elasticite/', name + '.mp4')):
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    import numpy as np
    from moviepy.video.io.bindings import mplfig_to_npimage
    import moviepy.editor as mpy
    duration = 3.
    fig_mpl, ax = plt.subplots(1, figsize=(6, 5), facecolor='white')

    def draw_elementary_pattern(ax, center):
        ax.add_artist(mpl.patches.Wedge(center, 1., 0, 180, width=.1))

    def make_frame_mpl(t):
        ax.cla()
        draw_elementary_pattern(ax, t/duration)
        return mplfig_to_npimage(fig_mpl) # RGB image of the figure

    animation = mpy.VideoClip(make_frame_mpl, duration=duration)
    animation.write_videofile('../files/2015-10-14_elasticite/' + name + '.mp4', fps=fps)
e.ipython_display(name)

Pour le plaisir, une autre animation

In [6]:
name = 'svm'
if not os.path.isfile(os.path.join('../files/2015-10-14_elasticite/', name + '.mp4')):
    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn import svm # sklearn = scikit-learn
    from sklearn.datasets import make_moons
    from moviepy.editor import VideoClip
    from moviepy.video.io.bindings import mplfig_to_npimage

    X, Y = make_moons(50, noise=0.1, random_state=2) # semi-random data

    fig, ax = plt.subplots(1, figsize=(4, 4), facecolor=(1,1,1))
    fig.subplots_adjust(left=0, right=1, bottom=0)
    xx, yy = np.meshgrid(np.linspace(-2,3,500), np.linspace(-1,2,500))

    def make_frame(t):
        ax.clear()
        ax.axis('off')
        ax.set_title("SVC classification", fontsize=16)

        classifier = svm.SVC(gamma=2, C=1)
        # the varying weights make the points appear one after the other
        weights = np.minimum(1, np.maximum(0, t**2+10-np.arange(50)))
        classifier.fit(X, Y, sample_weight=weights)
        Z = classifier.decision_function(np.c_[xx.ravel(), yy.ravel()])
        Z = Z.reshape(xx.shape)
        ax.contourf(xx, yy, Z, cmap=plt.cm.bone, alpha=0.8,
                    vmin=-2.5, vmax=2.5, levels=np.linspace(-2,2,20))
        ax.scatter(X[:,0], X[:,1], c=Y, s=50*weights, cmap=plt.cm.bone)

        return mplfig_to_npimage(fig)

    animation = VideoClip(make_frame, duration = 7)
    animation.write_videofile('../files/2015-10-14_elasticite/' + name + '.mp4', fps=fps)
e.ipython_display(name)

Pour notre cas, on veut animer nos grilles et on simplifie la syntaxte redondante:

In [7]:
name = 'test_grid'
import numpy as np

e = EdgeGrid(verb=False, structure=False)
def make_lames(e):
    return e.t*np.pi/duration

duration = 3.
e.make_anim(name, make_lames, duration=duration)
e.ipython_display(name)
In [8]:
name = 'test_grid2'
import numpy as np

e = EdgeGrid(verb=False, structure=False)

def make_lames(e):
    return e.lames[0, :] * np.pi +  e.t*np.pi/duration

duration = 3.
e.make_anim(name, make_lames, duration=duration)
e.ipython_display(name)