Conic SectionsΒΆ

../../_images/anim_conic.png

Animation control:

Visualization Frame Value
Contour Line position distance parameter per frame
Contour Line normal yz-component parameter per frame
Contour Line color color per frame
Shading and highlighting fixed to the coordinate axis
Axis coordinate constant

Based on the static plot from the Surface Contours example.

For this animation, the two parameters controlling the planar contours are varied with the frame: the distance of the plane from the origin, and the angle of the plane normal direction (parallel to the x-axis).

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import matplotlib.animation as animation
from matplotlib.colors import ListedColormap
import s3dlib.surface as s3d
import numpy as np

#.. Animated Conic Sections

# 1. Define function to examine .....................................

a, b, c, d = 0.8, 0.4, -.4, -.6
cd = (c+d)/2
p=.5
dist = [ a,  b,  0,  0,  c, cd,  d, -a ]
nang = [ 1,  p,  p,  0,  0, -p, -1, -1 ]
colors = ['C1','C2','C9','C0','C0','C1','C3' ]

def cone(rtz) :
    r,t,z = rtz
    R = np.abs(z)+0.001
    return R,t,z

def get_line(A,coneSurf) :
    # 0 < A < 1
    distance,ang = s3d.frame_to_value(A,dist,nang)
    color        = s3d.frame_to_value(A,colors   ,step=True)[0]
    phi = np.pi*ang/2
    direction = [ np.cos(phi),0,np.sin(phi)]
    contour = coneSurf.contourLines(distance,-distance,direction=direction,color=color)
    return contour.fade(0.2,15)
   
def indicator_by_A(fig, A, vOld=None) :
    symbol, blank = r'$\blacktriangleright$', r'$\blacksquare$'
    symbol, blank = r'$\blacktriangleleft$', r'$\blacksquare$'
    horz, vBot, vRng = 0.895, 0.22, 0.56
    vert = vBot + vRng*A
    if vOld is not None: 
        fig.text(horz+.001,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 .........................................
start_A = 0
rez=4

cmap = ListedColormap(colors)
surface = s3d.CylindricalSurface(rez,color='grey',cmap=cmap,lw=0.0)
surface.map_geom_from_op(cone)
surface.shade(.25).set_surface_alpha(.1)

line = get_line(start_A,surface)
# 3. Construct figure, add surface, plot ............................

fig = plt.figure(figsize=plt.figaspect(1))
ax = plt.axes(projection='3d')
ax.view_init(15)

plt.colorbar(surface.cBar_ScalarMappable, ax=ax, shrink=0.6, pad=.2, ticks=[] )
tL, tB, tD = 0.80, 0.25, 0.08
fig.text(tL,tB,     'Ellipses', ha='right')
fig.text(tL,tB+1*tD,'Parabolas', ha='right')
fig.text(tL,tB+2*tD,'Lines', ha='right')
fig.text(tL,tB+3.5*tD,'Hyperbolas', ha='right')
fig.text(tL,tB+5*tD,'Ellipses', ha='right')
fig.text(tL,tB+6*tD,'Circles', ha='right')

minmax = (-0.8,0.8)
ax.set(xlim=minmax, ylim=minmax, zlim=(-0.8,0.8))
ax.set_axis_off()

ax.add_collection3d(surface)
ax.add_collection3d(line)

prevIndicator = indicator_by_A(fig, start_A)

fig.tight_layout()
# 4. Animation ......................................................

def init_fig():
    return line,

def update_fig(frame):
    global line
    global prevIndicator
    ax.collections.remove(line)

    line = get_line(frame,surface)
    prevIndicator = indicator_by_A(fig, frame, prevIndicator)

    ax.add_collection3d(line)

    return line,

ani = FuncAnimation(fig, update_fig, frames=np.linspace(0.0, 1.0, 100),
                    init_func=init_fig, blit=False, repeat=True, interval=50)

print(">>>>>>>>>>>>>>> Animation completed, file save proceeds")
#ani.save('ZZZ.mp4')                                   # use for movie file.
ani.save(None,writer=animation.FFMpegFileWriter())    # use for temp files.
print(">>>>>>>>>>>>>>> Save completed, screen display proceeds")

plt.show()