Neurostories: creating videos of the flash-lag effect

This page recollects some variations on the flash-lag effect... and the way to easily and programmmatically generate those movies of the illusion.



Let's first initialize the notebook:

In [1]:
from __future__ import division, print_function
import numpy as np
np.set_printoptions(precision=6, suppress=True)
import os
%matplotlib inline
#%config InlineBackend.figure_format='retina'
%config InlineBackend.figure_format = 'svg'
import matplotlib.pyplot as plt
import proglog
proglog.notebook()
#%load_ext autoreload
#%autoreload 2

the simplest approach

In [2]:
__author__ = "Laurent Perrinet INT - CNRS"
__licence__ = 'BSD licence'

print('😎 Welcome to the script generating the movies 😎')

import os
home = os.environ['HOME']
figpath = '../files/'
def path2(fname):
    return os.path.join(figpath, fname)

import numpy as np
import gizeh as gz
import moviepy.editor as mpy

W, H = 1000, 600
duration = 2.
fps = 100
def create_movie(figname, r = 16,
                 duration = duration,
                 start = duration*.2,
                 stop = duration*.8, do_stop=False,
                 t_flash = 1.,
                 duration_flash = .02,
                 flash_fill=(0,1,0),
                 dot_fill=(1,0,0),
                 fps = fps,
                 W=W, H=H):
    flash = gz.rectangle(lx=r, ly=r, xy=(W/2., H/2.-r), fill=flash_fill)
    def make_frame(t):
        surface = gz.Surface(W, H, bg_color=(0, 0, 0))
        if np.abs(t-t_flash) < duration_flash: flash.draw(surface)
        if start < t < stop:
            if do_stop and t >= duration/2:
                flash.draw(surface)
                rect = gz.rectangle(lx=r, ly=r, xy=(W/2, H/2.+r), fill=dot_fill)
            else:
                rect = gz.rectangle(lx=r, ly=r, xy=(W*t/duration, H/2.+r), fill=dot_fill)
            rect.draw(surface)
        return surface.get_npimage()

    clip = mpy.VideoClip(make_frame, duration=duration)
    clip.write_videofile(path2(figname), fps=fps)
    return clip

figname = '2019-09-30_flash_lag.mp4'
if True: # not os.path.isfile(path2(figname)): 
    clip = create_movie(figname)
clip = mpy.VideoFileClip(path2(figname))
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
😎 Welcome to the script generating the movies 😎
Moviepy - Building video ../files/2019-09-30_flash_lag.mp4.
Moviepy - Writing video ../files/2019-09-30_flash_lag.mp4

HBox(children=(FloatProgress(value=0.0, description='t', max=200.0, style=ProgressStyle(description_width='ini…
Moviepy - Done !
Moviepy - video ready ../files/2019-09-30_flash_lag.mp4
Moviepy - Building video __temp__.mp4.
Moviepy - Writing video __temp__.mp4

HBox(children=(FloatProgress(value=0.0, description='t', max=200.0, style=ProgressStyle(description_width='ini…
Moviepy - Done !
Moviepy - video ready __temp__.mp4
Out[2]:
In [3]:
figname = '2019-09-30_flash_lag_stop.mp4'
if True: # not os.path.isfile(path2(figname)): 
    clip = create_movie(figname, do_stop=True)
clip = mpy.VideoFileClip(path2(figname))
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
Moviepy - Building video ../files/2019-09-30_flash_lag_stop.mp4.
Moviepy - Writing video ../files/2019-09-30_flash_lag_stop.mp4

HBox(children=(FloatProgress(value=0.0, description='t', max=200.0, style=ProgressStyle(description_width='ini…
Moviepy - Done !
Moviepy - video ready ../files/2019-09-30_flash_lag_stop.mp4
Moviepy - Building video __temp__.mp4.
Moviepy - Writing video __temp__.mp4

HBox(children=(FloatProgress(value=0.0, description='t', max=200.0, style=ProgressStyle(description_width='ini…
Moviepy - Done !
Moviepy - video ready __temp__.mp4
Out[3]:
In [4]:
t_flashes = [0.90, 0.95, 1, 1.05, 1.10]
n_flashes = len(t_flashes)
color_flashes = [(0, v, 1-v) for v in np.linspace(0, 1, n_flashes, endpoint=True)]
In [5]:
for i, (t_flash, flash_fill) in enumerate(zip(t_flashes, color_flashes)):
    figname = f'2019-09-30_flash_lag_{i}.mp4'
    if not os.path.isfile(path2(figname)): 
        clip = create_movie(figname, t_flash=t_flash, flash_fill=flash_fill)
    #clip = mpy.VideoFileClip(path2(figname))
    #clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)

mutiple horizontal panels: varrying timing

In [6]:
__author__ = "Laurent Perrinet INT - CNRS"
__licence__ = 'BSD licence'

print('😎 Welcome to the script generating the movies 😎')

import os
home = os.environ['HOME']
figpath = '../files/'
def path2(fname):
    return os.path.join(figpath, fname)

import numpy as np
import gizeh as gz
import moviepy.editor as mpy

W, H = 1000, 600
duration = 2.
fps = 100
def create_movie(figname, r = 16,
                 duration = duration,
                 start = duration*.2,
                 stop = duration*.8, do_stop=False,
                 #t_flashes = [1.05, 0.90, 1.10, 0.95, 1],
                 t_flashes = [1.05, .95, 1],
                 duration_flash = .05,
                 flash_fill=(0,1,0),
                 dot_fill=(1,0,0),
                 fps = fps,
                 W=W, H=H):
    
    n_flashes = len(t_flashes)
    color_flashes = [(0, v, 1-v) for v in np.linspace(0, 1, n_flashes, endpoint=True)]
    Hs = [v for v in np.linspace(0, H, 2*n_flashes+1, endpoint=True)] # all intermediate positions
    Hs = Hs[1::2] # from the first one, take one from two = +|+|+|+

    def make_frame(t):
        surface = gz.Surface(W, H, bg_color=(0, 0, 0))

        for i, (t_flash, flash_fill, H_) in enumerate(zip(t_flashes, color_flashes, Hs)):
            
            flash = gz.rectangle(lx=r, ly=r, xy=(W/2., H_-r), fill=flash_fill)

            if np.abs(t-t_flash) < duration_flash: flash.draw(surface)
            if start < t < stop:
                rect = gz.rectangle(lx=r, ly=r, xy=(W*t/duration, H_+r), fill=dot_fill)
                rect.draw(surface)
        return surface.get_npimage()

    clip = mpy.VideoClip(make_frame, duration=duration)
    clip.write_videofile(path2(figname), fps=fps)
    return clip

figname = '2019-09-30_flash_lag_parallel.mp4'
if True: # not os.path.isfile(path2(figname)): 
    clip = create_movie(figname)
clip = mpy.VideoFileClip(path2(figname))
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
😎 Welcome to the script generating the movies 😎
Moviepy - Building video ../files/2019-09-30_flash_lag_parallel.mp4.
Moviepy - Writing video ../files/2019-09-30_flash_lag_parallel.mp4

HBox(children=(FloatProgress(value=0.0, description='t', max=200.0, style=ProgressStyle(description_width='ini…
Moviepy - Done !
Moviepy - video ready ../files/2019-09-30_flash_lag_parallel.mp4
Moviepy - Building video __temp__.mp4.
Moviepy - Writing video __temp__.mp4

HBox(children=(FloatProgress(value=0.0, description='t', max=200.0, style=ProgressStyle(description_width='ini…
Moviepy - Done !
Moviepy - video ready __temp__.mp4
Out[6]:

mutiple horizontal panels: varrying positional shift

In [7]:
__author__ = "Laurent Perrinet INT - CNRS"
__licence__ = 'BSD licence'

print('😎 Welcome to the script generating the movies 😎')

import os
home = os.environ['HOME']
figpath = '../files/'
def path2(fname):
    return os.path.join(figpath, fname)

import numpy as np
import gizeh as gz
import moviepy.editor as mpy

W, H = 1000, 600
duration = 2.
fps = 100
def create_movie(figname, r = 16,
                 duration = duration,
                 start = duration*.2,
                 stop = duration*.8, do_stop=False,
                 shifts_flash=[0.5, -.5, .0],
                 duration_flash = .05,
                 flash_fill=(0,1,0),
                 dot_fill=(1,0,0),
                 fps = fps,
                 W=W, H=H):
    
    n_flashes = len(shifts_flash)
    color_flashes = [(0, v, 1-v) for v in np.linspace(0, 1, n_flashes, endpoint=True)]
    Hs = [v for v in np.linspace(0, H, 2*n_flashes+1, endpoint=True)] # all intermediate positions
    Hs = Hs[1::2] # from the first one, take one from two = +|+|+|+

    def make_frame(t):
        surface = gz.Surface(W, H, bg_color=(0, 0, 0))

        for i, (shift_flash, flash_fill, H_) in enumerate(zip(shifts_flash, color_flashes, Hs)):
            
            flash = gz.rectangle(lx=r, ly=r, xy=(W/2.+shift_flash*r, H_-r), fill=flash_fill)

            if np.abs(t-1.) < duration_flash: flash.draw(surface)
            if start < t < stop:
                rect = gz.rectangle(lx=r, ly=r, xy=(W*t/duration, H_+r), fill=dot_fill)
                rect.draw(surface)
        return surface.get_npimage()

    clip = mpy.VideoClip(make_frame, duration=duration)
    clip.write_videofile(path2(figname), fps=fps)
    return clip

figname = '2019-09-30_flash_lag_parallel_shift.mp4'
if True: # not os.path.isfile(path2(figname)): 
    clip = create_movie(figname)
clip = mpy.VideoFileClip(path2(figname))
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
😎 Welcome to the script generating the movies 😎
Moviepy - Building video ../files/2019-09-30_flash_lag_parallel_shift.mp4.
Moviepy - Writing video ../files/2019-09-30_flash_lag_parallel_shift.mp4

HBox(children=(FloatProgress(value=0.0, description='t', max=200.0, style=ProgressStyle(description_width='ini…
Moviepy - Done !
Moviepy - video ready ../files/2019-09-30_flash_lag_parallel_shift.mp4
Moviepy - Building video __temp__.mp4.
Moviepy - Writing video __temp__.mp4

HBox(children=(FloatProgress(value=0.0, description='t', max=200.0, style=ProgressStyle(description_width='ini…
Moviepy - Done !
Moviepy - video ready __temp__.mp4
Out[7]:
In [8]:
figname = '2019-09-30_flash_lag_parallel_shift_5.mp4'
if True: # not os.path.isfile(path2(figname)): 
    clip = create_movie(figname, shifts_flash=[0.5, -.25, -.5, .0, .25])
clip = mpy.VideoFileClip(path2(figname))
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
Moviepy - Building video ../files/2019-09-30_flash_lag_parallel_shift_5.mp4.
Moviepy - Writing video ../files/2019-09-30_flash_lag_parallel_shift_5.mp4

HBox(children=(FloatProgress(value=0.0, description='t', max=200.0, style=ProgressStyle(description_width='ini…
Moviepy - Done !
Moviepy - video ready ../files/2019-09-30_flash_lag_parallel_shift_5.mp4
Moviepy - Building video __temp__.mp4.
Moviepy - Writing video __temp__.mp4

HBox(children=(FloatProgress(value=0.0, description='t', max=200.0, style=ProgressStyle(description_width='ini…
Moviepy - Done !
Moviepy - video ready __temp__.mp4
Out[8]:

a more complex approach

In [9]:
import gizeh as gz
W, H = 500, 300
r, gray, t = 25., .3, 1.

surface = gz.Surface(W,H, bg_color=(1, 1, 1)) # white background
gradient = gz.ColorGradient(type="radial", stops_colors=[(0,(gray, gray, gray)), (1, (1, 1, 1))],
                            xy1=[0, 0], xy2=[0, 0], xy3=[0, r])
rf = gz.circle(r=r, xy=(W/2., H/2.), fill=gradient)
#rect = gz.rectangle(lx=.3*H, ly=.02*H, xy=(W*t/duration, H/2.), fill=(0,1,0), angle=np.pi/2)

rf.draw(surface)
surface.ipython_display()
Out[9]:
No description has been provided for this image

The flash-lag clock

And now the animation for the straight trajectory of a segment with perpendicular orientation:

In [3]:
import numpy as np
import gizeh as gz
import moviepy.editor as mpy

W, H = 1000, 600
duration = 1

figpath = '../files/2019-09-30_'
fps = 60

fix = gz.circle(r=5, xy=(W/2., H/2.), fill=(1, 0, 0))

def make_frame(t):

    surface = gz.Surface(W, H, bg_color=(0, 0, 0))
    
    # rect = gz.rectangle(lx=.3*H, ly=.02*H, xy=(W*t/duration, H/2.), fill=(0,1,0), angle=np.pi/2)
    # modul = 1 - .2*np.sin(2*np.pi*t/duration)
    # ymodul = 1 + .2*(np.cos(2*np.pi*t/duration)+1)
    lx = .4*H
    for theta in np.linspace(0, 2*np.pi, 50, endpoint=False):
        gray = .1
        rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(gray, gray, gray), angle=theta)
        rect.draw(surface)

    pastille = gz.circle(r=25, xy=(W/2., H/2.), fill=(0, 0, 0))
        
    theta = 2*np.pi*t/duration + np.pi
    rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(0,1,0), angle=theta)
    rect.draw(surface)
    if np.abs(np.sin(.5*(theta+np.pi/2))) < np.sin(np.pi/64):
        # print (theta, np.abs(np.tan(theta)), np.tan(np.pi/32), np.abs(np.tan(theta)) < np.tan(np.pi/32))
        print ('flash for ', theta)
        flash = gz.circle(r=5, xy=(W/2., H/2. - .48*H), fill=(1, 0, 0))
        flash.draw(surface)
    pastille.draw(surface)
    fix.draw(surface)
    return surface.get_npimage()

clip = mpy.VideoClip(make_frame, duration=duration)
#clip.write_videofile(figpath + 'clock.mp4', fps=fps) # Many options...

clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
t:   7%|▋         | 4/60 [00:00<00:01, 36.45it/s, now=None]
Moviepy - Building video __temp__.mp4.
Moviepy - Writing video __temp__.mp4

t:  33%|███▎      | 20/60 [00:00<00:01, 30.89it/s, now=None]
flash for  4.71238898038469
                                                            
Moviepy - Done !
Moviepy - video ready __temp__.mp4
Out[3]:

avec un flash trait

In [4]:
def make_frame(t):

    surface = gz.Surface(W, H, bg_color=(0, 0, 0))

    lx = .4*H
    for theta in np.linspace(0, 2*np.pi, 50, endpoint=False):
        gray = .1
        rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(gray, gray, gray), angle=theta)
        rect.draw(surface)

    pastille = gz.circle(r=25, xy=(W/2., H/2.), fill=(0, 0, 0))
        
    theta = 2*np.pi*t/duration + np.pi
    rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(0,1,0), angle=theta)
    rect.draw(surface)
    if np.abs(np.sin(.5*(theta+np.pi/2))) < np.sin(np.pi/64):
        print ('flash for theta=', theta, ', t=', t)
        flash = gz.rectangle(lx=.06*H, ly=2, xy=(W/2., H/2. - .47*H), fill=(1, 0, 0), angle=np.pi/2)
        flash.draw(surface)
    pastille.draw(surface)
    fix.draw(surface)
    return surface.get_npimage()

clip = mpy.VideoClip(make_frame, duration=duration)
#clip.write_videofile(figpath + 'clock.mp4', fps=fps) # Many options...

clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
t:   0%|          | 0/60 [00:00<?, ?it/s, now=None]
Moviepy - Building video __temp__.mp4.
Moviepy - Writing video __temp__.mp4

t:  37%|███▋      | 22/60 [00:01<00:01, 20.70it/s, now=None]
flash for theta= 4.71238898038469 , t= 0.25
                                                            
Moviepy - Done !
Moviepy - video ready __temp__.mp4

Out[4]:

avec plusieurs flash trait

In [5]:
duration = 3

def make_frame(t):

    surface = gz.Surface(W, H, bg_color=(0, 0, 0))
    lx = .4*H
    
    for theta in np.linspace(0, 2*np.pi, 50, endpoint=False):
        gray = .1
        rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(gray, gray, gray), angle=theta)
        rect.draw(surface)

    pastille = gz.circle(r=25, xy=(W/2., H/2.), fill=(0, 0, 0))
    N_spikes = 5
    for theta_ in np.linspace(0, 2*np.pi, N_spikes, endpoint=False):
        theta = 2*np.pi*t/duration + np.pi + theta_
        rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(0,1,0), angle=theta)
        rect.draw(surface)
        
        #if np.abs(np.cos(np.pi*(t/duration-.5)*N_spikes)) > np.cos(np.pi/32):
        if np.abs(np.sin(N_spikes*(theta_-theta)/2)) < np.sin(np.pi/64):
            print ('flash for theta=', theta, ', t=', t)
            flash = gz.rectangle(lx=.06*H, ly=5, xy=(W/2. + .47*H*np.cos(theta_), H/2. - .47*H*np.sin(theta_)), fill=(1, 0, 0), 
                                 angle=-theta_)
            flash.draw(surface)
        
    pastille.draw(surface)
    fix.draw(surface)
    return surface.get_npimage()

clip = mpy.VideoClip(make_frame, duration=duration)
#clip.write_videofile(figpath + 'clock.mp4', fps=fps)
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
t:   0%|          | 0/180 [00:00<?, ?it/s, now=None]
Moviepy - Building video __temp__.mp4.
Moviepy - Writing video __temp__.mp4

t:  12%|█▏        | 22/180 [00:00<00:05, 28.69it/s, now=None]
flash for theta= 3.7699111843077517 , t= 0.3
flash for theta= 5.026548245743669 , t= 0.3
flash for theta= 6.283185307179586 , t= 0.3
flash for theta= 7.5398223686155035 , t= 0.3
flash for theta= 8.79645943005142 , t= 0.3
t:  32%|███▏      | 58/180 [00:01<00:04, 29.47it/s, now=None]
flash for theta= 5.026548245743669 , t= 0.9
flash for theta= 6.283185307179586 , t= 0.9
flash for theta= 7.5398223686155035 , t= 0.9
flash for theta= 8.79645943005142 , t= 0.9
flash for theta= 10.053096491487338 , t= 0.9
t:  52%|█████▏    | 94/180 [00:03<00:02, 32.18it/s, now=None]
flash for theta= 6.283185307179586 , t= 1.5
flash for theta= 7.5398223686155035 , t= 1.5
flash for theta= 8.79645943005142 , t= 1.5
flash for theta= 10.053096491487338 , t= 1.5
flash for theta= 11.309733552923255 , t= 1.5
t:  72%|███████▏  | 130/180 [00:04<00:01, 31.22it/s, now=None]
flash for theta= 7.5398223686155035 , t= 2.1
flash for theta= 8.79645943005142 , t= 2.1
flash for theta= 10.053096491487338 , t= 2.1
flash for theta= 11.309733552923255 , t= 2.1
flash for theta= 12.566370614359172 , t= 2.1
t:  93%|█████████▎| 168/180 [00:05<00:00, 30.73it/s, now=None]
flash for theta= 8.79645943005142 , t= 2.7
flash for theta= 10.053096491487338 , t= 2.7
flash for theta= 11.309733552923255 , t= 2.7
flash for theta= 12.566370614359172 , t= 2.7
flash for theta= 13.82300767579509 , t= 2.7
                                                              
Moviepy - Done !
Moviepy - video ready __temp__.mp4
Out[5]:

avec plusieurs flash trait + plusieurs alternatives

In [6]:
duration = 3

def make_frame(t):

    surface = gz.Surface(W, H, bg_color=(0, 0, 0))
    lx = .4*H
    
    for theta in np.linspace(0, 2*np.pi, 50, endpoint=False):
        gray = .1
        rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(gray, gray, gray), angle=theta)
        rect.draw(surface)

    pastille = gz.circle(r=25, xy=(W/2., H/2.), fill=(0, 0, 0))
    N_spikes = 5
    theta_effects = [0, -7.5 * np.pi/180, -15 * np.pi/180]
    for theta_ in np.linspace(0, 2*np.pi, N_spikes, endpoint=False):
        theta = 2*np.pi*t/duration + np.pi + theta_
        rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(1, 1, 1), angle=theta)
        rect.draw(surface)
        
        #if np.abs(np.cos(np.pi*(t/duration-.5)*N_spikes)) > np.cos(np.pi/32):
        if np.abs(np.sin(N_spikes*(theta_-theta)/2)) < np.sin(np.pi/64):
            # print ('flash for theta=', theta, ', t=', t)
            for theta_effect, color in zip(theta_effects, [(1, 0.1, 0.1), (.1, 1., .1), (.1, 0.1, 1.)]):
                flash = gz.rectangle(lx=.06*H, ly=5, xy=(W/2. + .47*H*np.cos(theta_+theta_effect), H/2. - .47*H*np.sin(theta_+theta_effect)), fill=color, 
                                     angle=-theta_-theta_effect)
                flash.draw(surface)
        
    pastille.draw(surface)
    fix.draw(surface)
    return surface.get_npimage()

clip = mpy.VideoClip(make_frame, duration=duration)
#clip.write_videofile(figpath + 'clock.mp4', fps=fps)
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
t:   0%|          | 0/180 [00:00<?, ?it/s, now=None]
Moviepy - Building video __temp__.mp4.
Moviepy - Writing video __temp__.mp4

                                                              
Moviepy - Done !
Moviepy - video ready __temp__.mp4
Out[6]:

mouvement rectiligne avec plusieurs flash trait

In [7]:
duration = 1
fix = gz.circle(r=5, xy=(W/2., H/2.), fill=(0, 0, 1))
red_fix = gz.circle(r=5, xy=(W/2., H/2.), fill=(1, 0, 0))

def make_frame(t):

    surface = gz.Surface(W, H, bg_color=(0, 0, 0))
    lh = .1*H
    DX = .6*H
    for x in np.linspace(-DX/2, DX/2, 25, endpoint=True):
        gray = .1
        rect = gz.rectangle(lx=2, ly=lh, xy=(W/2 + x, H/2.), fill=(gray, gray, gray))
        rect.draw(surface)

    x = -DX/2 +  DX*t/duration
    rect = gz.rectangle(lx=2, ly=lh, xy=(W/2 + x, H/2. + 0*lh*1.2), fill=(1, 1, 1))
    rect.draw(surface)

    fix.draw(surface)
    if np.abs(x) < 10 :
        # print ('flash for theta=', theta, ', t=', t)
        shifts = [-25, 0, 25]
        for shift, color in zip(shifts, [(1, 0.1, 0.1), (.1, 1., .1), (.1, 0.1, 1.)]):
            flash = gz.rectangle(lx=2, ly=lh*.2, xy=(W/2+shift, H/2.-lh/2*1.4), fill=color)
            flash.draw(surface)
        # red_fix.draw(surface)
        
    return surface.get_npimage()

clip = mpy.VideoClip(make_frame, duration=duration)
clip.write_videofile(figpath + 'clock.mp4', fps=fps)
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
t:   0%|          | 0/60 [00:00<?, ?it/s, now=None]
Moviepy - Building video ../files/2019-09-30_clock.mp4.
Moviepy - Writing video ../files/2019-09-30_clock.mp4

t:   7%|▋         | 4/60 [00:00<00:01, 38.46it/s, now=None] 
Moviepy - Done !
Moviepy - video ready ../files/2019-09-30_clock.mp4
Moviepy - Building video __temp__.mp4.
Moviepy - Writing video __temp__.mp4

                                                            
Moviepy - Done !
Moviepy - video ready __temp__.mp4
Out[7]:

second principle

In [ ]:
#!youtube-dl https://www.youtube.com/watch\?v\=v30b5IAgwQw
fname = "20151115-Breaking Glass in Ultra Slow Motion _ 30000 FPS-v30b5IAgwQw.mp4"

# TODO: import movie, reduce size and then montage it with its reversed-time version

some book keeping for the notebook

In [9]:
!rm __temp__.mp4 debug.log
rm: debug.log: No such file or directory
In [9]:
%load_ext watermark
%watermark
2019-10-01T16:58:36+02:00

CPython 3.7.4
IPython 7.8.0

compiler   : Clang 10.0.1 (clang-1001.0.46.4)
system     : Darwin
release    : 18.7.0
machine    : x86_64
processor  : i386
CPU cores  : 36
interpreter: 64bit