Dual Surface Face ColorΒΆ

Animation control:

Visualization

Frame Value

Surface geometry

constant

Surface position

fixed to the coordinate axis

Surface color

axis per frame using map_cmap_from_normals

Shading and highlighting

illumination direction per frame

Axis coordinate

elev and azim per frame using view_init

Surface construction is based on the Inner and Outer Surface Coloring example. Color mapping is based on the view in the map_cmap_from_normals method, as in the Inner/Outer Surface Colormap example. This provides front and back surface coloring (direction=ax). Now, both the elev and azim change the shading per frame, same as the Python Cube animation, with the addition of the view information provided by the ax=ax parameter changing surface color.

import copy
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

#.. Elev and Azim changes setting illumination direction and surface coloring.

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

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

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

def fig_8_knot(t,isInner) :
    T = 2*np.pi*t
    x = (2 + np.cos(2*T))*np.cos(3*T)
    y = (2 + np.cos(2*T))*np.sin(3*T)
    z = 3*np.sin(4*T) 
    f = 0.8 if isInner else 1.2
    return f*x,f*y,f*z

inn_eight = lambda t : fig_8_knot(t,True)
out_eight = lambda t : fig_8_knot(t,False)

# 2. Setup and map surface .........................................
rez=8
view_elev, view_azim, illum_dir = 0, 0, [1,1,1] 

bcmap = cmu.binary_cmap('orange', 'yellowgreen', name='orng_yg' )
line_1 = s3d.ParametricLine(rez,inn_eight)
line_2 = s3d.ParametricLine(rez,out_eight)
knot = line_1.get_surface_to_line(line_2)

orig_knot = copy.copy(knot)

# 3. Construct figure, add surface plot ............................
minmax = (-3,3)
fig = plt.figure(figsize=plt.figaspect(1), facecolor='black')
ax = plt.axes(projection='3d', facecolor='black')
ax.set(xlim=minmax,ylim=minmax,zlim=minmax)
ax.set_axis_off()

knot.map_cmap_from_normals(direction=ax,cmap=bcmap)
knot.shade(0.1,direction=illum_dir,ax=ax).hilite(.5,direction=illum_dir,ax=ax)
ax.add_collection3d(knot)

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

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

def update_fig(frame):
    view_elev = 360*frame
    view_azim = 360*frame
    if view_elev >= 270 : view_elev = view_elev - 360
    ax.view_init( elev=view_elev, azim=view_azim )

    knot = copy.copy(orig_knot)
    knot.map_cmap_from_normals(direction=ax,cmap=bcmap)
    knot.shade(0.1,direction=illum_dir,ax=ax).hilite(.5,direction=illum_dir,ax=ax)

    ax.add_collection3d(knot)
    return

anim = FuncAnimation(fig, update_fig, frames, interval=interval, repeat=True)
anim.save('fig_8_knot.html',writer='html')

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