<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 An animation reproducing a Fermat's Library gif, posted on twitter
Update
Step1:  Define data that will be updated by each animation frame
Step2:  Set the plot layout
Step3:  The black disk is defined as a Plotly shape, and the withe diameters as quadratic B&eacute;zier curves defined by
 three colinear control points
<ASSISTANT_TASK:>
Python Code:
import numpy as np
from numpy import pi
import plotly.graph_objects as go 
u = np.array([0.5 + 0.5*np.exp(2*k*np.pi*1j/8) for k in range(8)], dtype=np.complex)
Explanation: 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}$
End of explanation
fig = go.Figure(go.Scatter(
           x = u.real,  
           y= u.imag,
           mode='markers',
           marker=dict( size=0.01, color='white'),
           name='moving_pts',
           ))
frames=[]
for m in range(64):
    w = np.exp(-1j*m*pi/8)*0.5+np.exp(1j*m*pi/8)*(u-0.5)
    frames.append(go.Frame(data=[go.Scatter(
                                      x= w.real,
                                      y=w.imag, 
                                      marker=dict(size=15, color='white')    
                                 )],
                           traces=[0]))
fig.update(frames=frames);                           
Explanation: Define data that will be updated by each animation frame:
End of explanation
axis = dict(visible=False,  
            range=[-1.1, 1.01],
            autorange=False)
fig.update_layout(
            title='Math is Fun',
            width=600,
            height=600,
            showlegend=False,
            xaxis=axis,
            yaxis=axis,
            hovermode='closest',
            updatemenus=[dict(type='buttons',
                              showactive=False,
                              y=1,
                              x=1.2,
                              xanchor='right',
                              yanchor='top',
                              pad=dict(l=10),
                              buttons=[dict(label='Play',
                                            method='animate',
                                            args=[None, dict(frame=dict(duration=150, redraw=False), 
                                            transition=dict(duration=80),
                                            fromcurrent=True,
                                            mode='immediate'
                                                )]
                                            )]
                            )]
           );
Explanation: Set the plot layout:
End of explanation
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
fig.add_shape(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_color= 'rgba(10,10,10, 0.9)'))
#define the shapes for  the 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
    fig.add_shape(dict(type= 'path',
                       path= f'M{x0}, {y0} Q 0.0,  0.0 {x1}, {y1}',                     
                       line= dict(color= 'white', 
                                  width=0.75)
                                ))   
from plotly.offline import download_plotlyjs, init_notebook_mode,  iplot
init_notebook_mode(connected=True)
iplot(fig)
from IPython.core.display import HTML
def  css_styling():
    styles = open("./custom.css", "r").read()
    return HTML(styles)
css_styling()
Explanation: The black disk is defined as a Plotly shape, and the withe diameters as quadratic B&eacute;zier curves defined by
 three colinear control points:
End of explanation
<END_TASK>