# Colormap Frame Animation¶

Apparent movement of a static geometric object by changing the colormapping reference per frame. Transparent sections of the colormaps are used to ‘hide’ portions of the geometry per frame. Animation control:

Visualization Frame Value
Surface geometry constant
Surface position constant
Surface colormap colormap position per frame
Axis coordinate constant

Following colormaps were used:

```import copy
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
import matplotlib.animation as animation
import s3dlib.surface as s3d
import s3dlib.cmap_utilities as cmu

#.. Annimated colormap

# 1. Define functions to examine ....................................
wdth, subW = 0.4, 0.4
elev, azim = 90, -30
illum = s3d.rtv([1,-1,1],elev,azim)

def Torus(rez,width=wdth ) :
def fold(rtz,width) :
r,t,z = rtz
Z = width*np.sin(z*np.pi)/2
R = 1 + width*np.cos(z*np.pi)/2
return R,t,Z
surface = s3d.CylindricalSurface(rez,basetype='tri_s')
surface.map_geom_from_op( lambda rtz : fold(rtz,width)    )
return surface

def Trefoil(rtz) :
r,t,z = rtz
rw = 1-wdth/2
X = rw*(np.sin(t)+2*np.sin(2*t))
Y = rw*(np.cos(t)-2*np.cos(2*t))
R0,T,Z = s3d.CylindricalSurface.coor_convert([X,Y,z])   # cylindrical coor
R = R0 + r - rw
Z = z - np.sin(3*t)
return R,T,Z

def shift(rtz, os=0) :
r,t,z = rtz
T = np.mod(t+os,np.full(len(t),2*np.pi))
return T

def ballCoor(rtp,os) :
xyz = s3d.SphericalSurface.coor_convert(rtp,True)
rtz = s3d.CylindricalSurface.coor_convert(xyz)
rtz = np.array(rtz)
rtz[1,:] = rtz[1,:] - os
rtz = Trefoil(rtz)
xyz = s3d.CylindricalSurface.coor_convert(rtz,True)
return xyz

# 2. Setup and map surfaces .........................................
rez, offset = 6, 0

cyan2clear = cmu.hsv_cmap_gradient( [.5,1,1,1], [.5,1,1,0] )
clear = cmu.hsv_cmap_gradient( [.5,1,1,0], [.5,1,1,0] )
cmap1 = cmu.stitch_cmap( cyan2clear, clear,bndry=[0.075], name='cmap1' )
cmap2 = cmu.stitch_cmap('inferno_r', clear,bndry=[0.58], name='cmap2' )

surface1 = Torus(rez)
surf1 = copy.copy(surface1)
surface1.map_cmap_from_op( lambda rtz : shift(rtz,offset), cmap1)
surface1.map_geom_from_op( Trefoil )

surface2 = Torus(rez, subW*wdth)
surf2 = copy.copy(surface2)
surface2.map_cmap_from_op( lambda rtz : shift(rtz,offset), cmap2)
surface2.map_geom_from_op( Trefoil )

ball = s3d.SphericalSurface(5,'octa',color=[0,1,1,1]).domain(wdth/2)
ball.clip(lambda c : np.less_equal(c[1],[0]), usexyz=True )
ball.map_cmap_from_op(lambda c: s3d.SphericalSurface.coor_convert(c,True)[1], wt_cy)
ball.transform(translate=[1,0,0])
ball0 = copy.copy(ball)
ball0.map_geom_from_op(lambda c: ballCoor(c,offset), returnxyz=True)

ring = surface1 + surface2 + ball0

# 3. Construct figure, add surfaces, and plot ......................
fig = plt.figure(figsize=plt.figaspect(1))
info = str(surface1)+'\n'+str(surface2)
text = fig.text(0.02, 0.02, info, color='grey', fontsize='small' )
ax = plt.axes(projection='3d')
minmax = (-2,2)
ax.set(xlim=minmax, ylim=minmax, zlim=minmax )
ax.set_axis_off()
ax.set_proj_type('ortho')
ax.set_facecolor( [ 0, 0, 0 ] )
ax.view_init(elev,azim)

# 4. Animation ......................................................

def init_fig():
return ring,

def update_fig(frame):
global ring

ax.collections.remove(ring)

offset = frame*(2*np.pi)

surface1 = copy.copy(surf1)
surface1.map_cmap_from_op( lambda rtz : shift(rtz,offset), cmap1)
surface1.map_geom_from_op( Trefoil )
surface2 = copy.copy(surf2)
surface2.map_cmap_from_op( lambda rtz : shift(rtz,offset), cmap2)
surface2.map_geom_from_op( Trefoil )
ball0 = copy.copy(ball)
ball0.map_geom_from_op(lambda c: ballCoor(c,offset), returnxyz=True)

ring = surface1 + surface2 + ball0