An animation reproducing a Fermat's Library gif, posted on twitter¶

Update: The explanation of the rectilinear motion of the eight points in this animation is given here.

Fermat's library, @fermatslibrary, posted on twitter a gif https://twitter.com/fermatslibrary/status/862659602776805379 illustrating eight points moving inside a circle. No explanation of the motion was given. Here I reproduce it via Python Plotly.

Following each particular point one notices that it moves on a diameter of the greater circle.

The white rays intersect the circle (of radius R=1) at the $16^{th}$ roots of unity. The eight points lie at each time during their motion on a circle of radius 1/2, and the center at the middle of a ray of the greater circle.

If at the time t=0, corresponding to the initial frame, the smaller circle has the center $(0.5, 0)$, and radius r=1/2, then the points at this time are represented by the complex numbers $u[k]=0.5+0.5\cdot e^{2\pi j k/8}$, where $e^{2\pi j k/8}$, $k=\overline{0,7}$, are the $8^{th}$ roots of unity. The $m^{th}$ frame of the animation displays the position of points obtained from the initial ones, as follows:

• rotate the center 0.5+0j about O, by $\theta_m=-2 m \pi/16$ and get the new center $C_m$;
• place on the circle of center $C_m$ and radius r=0.5, the points $u[k]-0.5$ rotated about O with $-\theta_m$. Hence in the $m^{th}$ frame we plot the points $w[k]=e^{-m\pi j/8}0.5+e^{m\pi j/8}(u[k]-0.5)$, $k=\overline{0,7}$
In [1]:
import numpy as np
from numpy import pi
import plotly.plotly as py
from plotly.grid_objs import Grid, Column
import time

In [2]:
py.sign_in('empet', 'api_key')

In [3]:
u=np.array([0.5+0.5*np.exp(2*k*np.pi*1j/8) for k in range(8)], dtype=np.complex)

In [4]:
my_columns=[Column(u.real, 'x0'), Column(u.imag, 'y0')]
for m in range(64):
w=np.exp(-1j*m*pi/8)*0.5+np.exp(1j*m*pi/8)*(u-0.5)
my_columns.append(Column(w.real, 'x{}'.format(m+1)))
my_columns.append(Column(w.imag, 'y{}'.format(m+1)))
grid = Grid(my_columns)

Out[4]:
u'https://plot.ly/~empet/14316/'

Define data that will be updated by each animation frame:

In [5]:
data=[dict(type='scatter',
xsrc=grid.get_column_reference('x0'),
ysrc= grid.get_column_reference('y0'),
mode='markers',
marker=dict(symbol='dot', size=0.01, color='white'),
name='moving_pts',
)]

In [6]:
frames=[]
for m in range(64):
frames.append(dict(data=[dict(type='scatter',
xsrc=grid.get_column_reference('x{}'.format(m+1)),
ysrc= grid.get_column_reference('y{}'.format(m+1)),
marker=dict(symbol='dot', size=15, color='white')
)],
traces=[0]
)
)


Set the plot layout:

In [7]:
axis=dict(showline=False,
zeroline=False,
showgrid=False,
showticklabels=False,
range=[-1.1,1.01],
autorange=False,
title=''
)

layout=dict(title='Math is Fun',
autosize=False,
width=600,
height=600,
showlegend=False,
xaxis=dict(axis),
yaxis=dict(axis),
hovermode='closest',
shapes=[],
showactive=False,
y=1,
x=1.2,
xanchor='right',
yanchor='top',
buttons=[dict(label='Play',
method='animate',
args=[None, dict(frame=dict(duration=180, redraw=False),
transition=dict(duration=200),
fromcurrent=True,
mode='immediate'
)]
)]
)]
)


The black disk is defined as a Plotly shape, and the withe diameters as quadratic Bézier curves defined by three colinear control points:

In [8]:
z=np.array([np.exp(2*k*np.pi*1j/16) for k in range(16)], dtype=np.complex)#the 16^th roots of unity

In [9]:
layout['shapes'].append(dict(type= 'circle',
layer= 'below',
xref= 'x',
yref='y',
fillcolor= 'rgba(10,10,10, 0.9)',
x0= -1.01,
y0= -1.01,
x1= 1.01,
y1= 1.01,
line= dict(color= 'rgba(10,10,10, 0.9)')
)
)
#define the shapes of eight diameters
for k in range( 8):
x0=z[k].real
y0=z[k].imag
x1=z[k+8].real
y1=z[k+8].imag
layout['shapes'].append(dict(type= 'path',
path= 'M' + str(x0)+', '+str(y0)+' Q'+str(0.0)+', '+str(0.0)+ ' '+str(x1)+', '+str(y1),
line= dict(color= 'white', width=0.75)
))

In [10]:
fig=dict(data=data, layout=layout, frames=frames)
py.icreate_animations(fig, filename='Fermat-exmay11'+str(time.time()))

Out[10]:
In [1]:
from IPython.core.display import HTML
def  css_styling():