In [ ]:
from ipycanvas import Canvas, hold_canvas

In [ ]:
import numpy as np

In [ ]:
from math import pi, cos, sin

In [ ]:
def draw(canvas, t):
size = 1000
step = 20
t1 = t / 1000.

x = 0
while x < size + step:
y = 0
while y < size + step:
x_angle = y_angle = 2 * pi

angle = x_angle * (x / size) + y_angle * (y / size)

particle_x = x + 20 * cos(2 * pi * t1 + angle)
particle_y = y + 20 * sin(2 * pi * t1 + angle)

canvas.fill_circle(particle_x, particle_y, 6)

y = y + step

x = x + step

In [ ]:
def fast_draw(canvas, t):
"""Same as draw, but using NumPy and the vectorized version of fill_circle: fill_circles"""
size = 1000
step = 20
t1 = t / 1000.

x = np.linspace(0, size, int(size / step))
y = np.linspace(0, size, int(size / step))
xv, yv = np.meshgrid(x, y)

x_angle = y_angle = 2 * pi

angle = x_angle * (xv / size) + y_angle * (yv / size)

particle_x = xv + 20 * np.cos(2 * pi * t1 + angle)
particle_y = yv + 20 * np.sin(2 * pi * t1 + angle)

canvas.fill_circles(particle_x, particle_y, 6)

In [ ]:
size = 1000
canvas = Canvas(width=size, height=size)
canvas.fill_style = '#fcba03'
canvas


1: Using from time import sleep and fill_circle¶

Worst approach: Slow locally, slow using a remote server (MyBinder)

In [ ]:
from time import sleep

for i in range(200):
with hold_canvas(canvas):
canvas.clear()

draw(canvas, i * 20.)

sleep(20 / 1000.)


2: Using canvas.sleep and fill_circle¶

This caches the entire animation before sending it to the front-end. This results in a slow execution (caching), but it ensure a smooth animation on the front-end whichever the context (local or remote server).

Slow to execute, smooth animation

In [ ]:
with hold_canvas(canvas):
for i in range(200):
canvas.clear()

draw(canvas, i * 20.)

canvas.sleep(20)

In [ ]:
canvas


3: Using from time import sleep and the vectorized fill_circles¶

Super fast locally, can be fast on a remote server if the latency is correct

In [ ]:
from time import sleep

for i in range(200):
with hold_canvas(canvas):
canvas.clear()

fast_draw(canvas, i * 20.)

sleep(20 / 1000.)


4: Using canvas.sleep and the vectorized fill_circles¶

Best approach: Super fast locally, super fast on a remote server

In [ ]:
with hold_canvas(canvas):
for i in range(200):
canvas.clear()

fast_draw(canvas, i * 20.)

canvas.sleep(20)


Conclusion¶

Always use hold_canvas!

As much as possible, try to use the vectorized version of the base methods if you want to exectute them multiple times (fill_circles, fill_rects etc).

If you can, make use of canvas.sleep instead of from time import sleep so that the entire animation is sent at once to the front-end, making a smoother animation whatever the server latency.