Catenoid to HelicoidΒΆ

Animation control:

Visualization

Frame Value

Surface geometry

functional parameter per frame

Surface position

fixed to the coordinate axis

Surface color

color per frame

Shading and highlighting

fixed to the coordinate axis

Axis coordinate

constant

Based on the static plots from the Surface Displacement Vector Field and Parametric Set of Surfaces 2 examples.

A parametrization of the deformation is given at Helicoid transformation

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

#.. Helicoid Transformation Animation

# 0. Define animation control parameters ............................

totalTime, f_domain, numFrames = 4, (-1.0,1.0), 80  # time in seconds
frames=np.linspace(*f_domain, numFrames, endpoint=False)
interval = int(1000.0*totalTime/numFrames)          # milliseconds

# 1. Define functions to examine ....................................

def catenoid_helicoid(rtz, A) :
    r,t,z = rtz
    theta = A*np.pi  #  -1 < A < 1
    cosT, sinT = np.cos(theta), np.sin(theta)
    U, V = t, z   
    x =  cosT * np.sinh(V) * np.sin(U) +   sinT * np.cosh(V) * np.cos(U)
    y = -cosT * np.sinh(V) * np.cos(U) +   sinT * np.cosh(V) * np.sin(U)
    Z = ( U/np.pi- 1.0 ) *cosT +  V * sinT
    return x,y,Z

def colormap_by_A(A) :
    hue = (A + 1.0) / 2.0
    return cmu.hsv_cmap_gradient( [hue,1.0,0.25], [hue,0.5,1],smooth=1.6 )

def indicator_by_A(fig, A, vOld=None) :
    symbol, blank = r'$\blacktriangleright$', r'$\blacksquare$'
    horz, vCen, vRng = 0.8, 0.5, 0.28
    vert = vCen + vRng*A
    if vOld is not None: 
        fig.text(horz,vOld,blank, ha='right', va='center', fontsize='x-large', color='w')
    fig.text(horz,vert,symbol, ha='right', va='center', fontsize='large')
    return vert

# 2. Setup and map surfaces .........................................
rez, start_F = 5, -1.0

surface = s3d.CylindricalSurface(rez, basetype='squ_s', cmap=cmu.hue_cmap())
surface.map_geom_from_op( lambda rtz : catenoid_helicoid(rtz,start_F), returnxyz=True )

# 3. Construct figures, add surface, plot ...........................

fig = plt.figure(figsize=plt.figaspect(1))
ax = plt.axes(projection='3d', aspect='equal')
cbar = plt.colorbar(surface.cBar_ScalarMappable, ax=ax, ticks=np.linspace(-1,1,5), shrink=0.6 )
cbar.set_label(r'$\theta$ parameter', rotation=270, labelpad = 15)
cbar.ax.set_yticklabels([r'-$\pi$',r'-$\pi$/2','0',r'$\pi$/2',r'$\pi$'])
# surface mapping placed here to change colormap after colorbar defined.
surface.map_cmap_from_op( lambda rtz : rtz[0],colormap_by_A(start_F))
prevIndicator = indicator_by_A(fig, start_F)
# ....
minmax = (-1.2,1.2)
ax.set(xlim=minmax, ylim=minmax, zlim=minmax )
ax.view_init(25, -28)
ax.set_axis_off()

ax.add_collection3d(surface)

fig.tight_layout(pad=1)
#plt.show()

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

def update_fig(frame):
    global surface
    global prevIndicator
    surface.remove()

    surface = s3d.CylindricalSurface(rez, basetype='squ_s', antialiased=True)
    surface.map_geom_from_op( lambda rtz : catenoid_helicoid(rtz,frame), returnxyz=True )
    surface.map_cmap_from_op( lambda rtz : rtz[0],colormap_by_A(frame))
    prevIndicator = indicator_by_A(fig, frame, prevIndicator)

    ax.add_collection3d(surface)
    return surface,
 
anim = FuncAnimation(fig, update_fig, frames, interval=interval, repeat=True)
anim.save('cat2heli.html',writer='html')

msg = "saved {} frames, values: [{:.3f} to {:.3f}] @ {} milliseconds/frane"
print(msg.format(numFrames,np.min(frames),np.max(frames),interval))