Elliptic CurvesΒΆ

../../_images/anim_elliptic_curves_a.webp

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

Similar to the static plot from the Elliptic Curve example, the elliptic curve is defined, for coefficients a and b, as:

y2 = x3 + ax + b

Rearranging the above equation:

b = y2 - x3 - ax

So, within a 3-D space (x,y,a):

b = f(x,y,a)

Contour surfaces of constant b are shown above. Elliptic curves are the contour lines at the surface intersections with constant a planes.

In a similar manner, the initial equation can be arranged as:

a = ( y2 - b)/x - x2

So, within a 3-D space (x,y,b):

a = f(x,y,b)

In this case Contour surfaces of constant a are shown below. Here, elliptic curves are the contour lines at the surface intersections with constant b planes.

../../_images/anim_elliptic_curves_b.webp

The following script is used for both plots using the boolean value of isAvar.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm,colors,colormaps
from matplotlib.animation import FuncAnimation
import s3dlib.surface as s3d
import s3dlib.pntcloud as ptc
import s3dlib.cmap_utilities as cmu

isAvar = True   # controls if independent variable is a or b.

totalTime, f_domain, numFrames = 10, (0.0,1.0), 100   # time in seconds
frames=np.linspace(*f_domain, numFrames, endpoint=False)
interval = int(1000.0*totalTime/numFrames)            # milliseconds
frame_to_time = lambda f : 2*f if f<0.5 else 2*(1-f)  # forward to reverse sequence

def indicator_by_A(fig, A, vOld=None) :
    symbol, blank = r'$\blacktriangleright$', r'$\blacksquare$'
    horz, vBot, vRng = 0.82, 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 elliptic3D(xyz,isAvar) :
    x,y,z = xyz
    if isAvar :
        f = y**2 - (x**3 + z*x)    # f = b(x,y,a)
    else :
        f = ( y**2 - z)/x - x**2   # f = a(x,y,b)
    return f

drez, dmn, cmap = 9.99, [-3,3], cmu.section_cmap('jet',.15,.85,'subjet')

sdmn = np.array( [-2,2])                      #  surface value range (a or b)
Wabs =   lambda t : sdmn[0] + (sdmn[1]-sdmn[0])*t 
Fcolor = lambda v : cmap(  (v-sdmn[0])/(sdmn[1]-sdmn[0])  )
ell3d =  lambda xyz : elliptic3D(xyz,isAvar)

# 2. Setup and map surface .........................................
t=0
Fo = Wabs(t)

cloudObj = ptc.Point3DCloud(drez,domain=dmn)
cloudObj.map_vals_from_op(ell3d)

surface = cloudObj.valsurf(Fo,color=Fcolor(Fo))
if not isAvar : surface.clip(lambda c : np.abs(c[0])>0.01 ) # remove center yz-plane

lines = surface.contourLines(-2,-1.01,.005,1.01,2,color='k')

# 3. Construct figures, add surfaces, and plot ....................
ticks = [-3,-2,-1,0,1,2,3]
infoA = r'b = $y^2 - x^3 - ax$'
infoB = r'a = $\frac{y^2 -b}{x} - x^2$'
info =    infoA if isAvar else infoB
zlabel =    'a' if isAvar else 'b'
cbarlabel = 'b' if isAvar else 'a'
fig = plt.figure(figsize=(5,4))
fig.text(0.75,0.95,info, ha='center', va='top', fontsize='x-large')
fig.text(0.1,0.85,'(x,y,'+zlabel+')', ha='left', va='top', fontsize='large')
ax = plt.axes(projection='3d', aspect='equal')
ax.view_init(21)
ax.set(xticks=ticks, yticks=ticks, zticks=ticks,
       xlabel='x',ylabel='y',zlabel=zlabel)
norm = colors.Normalize(sdmn[0],sdmn[1])
scmp = cm.ScalarMappable(norm=norm,cmap=cmap)
cbar = plt.colorbar(scmp, ax=ax,  shrink=0.6, pad=.12, ticks=ticks )
cbar.set_label(cbarlabel, rotation=0, labelpad = 5, fontsize='x-large')
prevIndicator = indicator_by_A(fig, t)

ax.add_collection3d(surface.shade(ax=ax).set_surface_alpha(.4))
ax.add_collection3d(lines.fade(.1))
s3d.add_boxCorner(ax,dmn)

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

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

    Fo = Wabs(frame_to_time(frame))
    surface = cloudObj.valsurf(Fo,color=Fcolor(Fo))
    if not isAvar : surface.clip(lambda c : np.abs(c[0])>0.01 ) # remove center yz-plane
    lines = surface.contourLines(-2,-1.01,.005,1.01,2,color='k')
    prevIndicator = indicator_by_A(fig, frame_to_time(frame), prevIndicator)
    ax.add_collection3d(surface.shade(ax=ax).set_surface_alpha(.4))
    ax.add_collection3d(lines.fade(.1))

    return

anim = FuncAnimation(fig, update_fig, frames, interval=interval, repeat=True)
anim.save('elliptic_curves_'+zlabel+'.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')