Implicit SurfaceΒΆ
Animation control:
Visualization |
Frame Value |
|---|---|
Surface geometry |
functional parameter per frame |
Surface position |
constant |
Surface color |
color per frame |
Shading and highlighting |
fixed to the coordinate axis |
Axis coordinate |
constant |
The above animation uses the same function as the static plot from the Contour Surface within a Volume example. For this example, a cloud is first constructed and then used to generate multiple cloud surfaces for the animation. This improves computational efficiency as opposed to using multiple implsurf method calls.
The frame function dualcusp was used to increase the density of functional values near zero.
As the functional value, Fo, changes sign, the outward normal of the surface reverses. For consistent shading, the surface evert method is used, as highlighted if the following script.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import s3dlib.surface as s3d
import s3dlib.pntcloud as ptc
totalTime, f_domain, numFrames = 10, (0.0,1.0), 121 # time in seconds
frames=np.linspace(*f_domain, numFrames, endpoint=True)
interval = int(1000.0*totalTime/numFrames) # milliseconds
def dualcusp(t) :
# used to increase density of Fo values near zero.
y = -np.cos(2*t*np.pi)
y = np.where(y>0.0,-y,y)
y = np.where(t>0.5,-2-y,y)
return y+1
frame_to_A = lambda t : (1.0 + dualcusp(t))/2
frame_to_Fo = lambda t : -0.001 + 0.42*dualcusp(t)
def indicator_by_A(fig, A, vOld=None) :
symbol, blank = r'$\blacktriangleright$', r'$\blacksquare$'
horz, vBot, vRng = 0.80, 0.22, 0.56
vert = vBot + vRng*A
if vOld is not None: #.. cover current > symbol
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
# 1. Define function to examine .....................................
def func3D(xyz) :
x,y,z = xyz
f = (x+y+z)*np.exp(-3*(x**2 + y**2 + z**2) )
return f
# 2. Setup and map cloud and surface ................................
drez, dmn, cmap = 5, [-1,1], 'jet'
t=0.15
Fo = frame_to_Fo(t)
cloudObj = ptc.Point3DCloud(drez,domain=dmn,cmap=cmap)
cloudObj.map_vals_from_op(func3D)
cloudObj.map_cmap_from_cloudvals()
surface = cloudObj.valsurf(Fo)
if Fo > 0.0 : surface.evert()
# 3. Construct figures, add surfaces, and plot ....................
ticks = [-1,-.5,0,.5,1]
info = r"Fo = f(x,y,z) = (x+y+z)$e^{-3(x^2+y^2+z^2)}$ "
fig = plt.figure(figsize=(5,4))
fig.text(0.5,0.98,info, ha='center', va='top', fontsize='x-large')
ax = plt.axes(projection='3d', aspect='equal')
ax.set(xticks=ticks, yticks=ticks, zticks=ticks,
xlabel='x',ylabel='y',zlabel='z')
scmp = cloudObj.cBar_ScalarMappable
cbar = plt.colorbar(scmp, ax=ax, shrink=0.6, pad=.12 )
cbar.set_label('Fo', rotation=0, labelpad = 5, fontsize='x-large')
prevIndicator = indicator_by_A(fig, frame_to_A(t))
ax.add_collection3d(surface.shade().hilite(0.5))
s3d.add_boxCorner(ax,dmn)
fig.tight_layout(pad=1)
plt.show()
# 4. Animation ======================================================
def update_fig(frame):
global surface,prevIndicator
surface.remove()
Fo = frame_to_Fo(frame)
surface = cloudObj.valsurf(Fo)
if Fo > 0.0 : surface.evert()
prevIndicator = indicator_by_A(fig, frame_to_A(frame), prevIndicator)
ax.add_collection3d(surface.shade().hilite(.5))
return
anim = FuncAnimation(fig, update_fig, frames, interval=interval, repeat=True)
anim.save('func3D_XYZ.html',writer='html')
msg = "saved {} frames, values: [{:.3f} to {:.3f}] @ {} milliseconds/frane"
print(msg.format(numFrames,np.min(frames),np.max(frames),interval))
print('done')
