Setup¶

In [1]:
import math
from math import pi
from math import asin
from math import cos
from math import sin
from math import sqrt as mS
import matplotlib
from matplotlib.animation import FuncAnimation as FA
from matplotlib.patches import Circle as mpC
from matplotlib.patches import Polygon as mpL
from matplotlib.patches import Rectangle as mpR
import matplotlib.pyplot as plt
import numpy as np

Constants¶

In [2]:
body = "#4487F0"
dot = "#595959"
In [3]:
#Clear axes.
def clearAx(ax):
    ax.spines["top"].set_visible(False)
    ax.spines["right"].set_visible(False)
    ax.spines["bottom"].set_visible(False)
    ax.spines["left"].set_visible(False)
    ax.set_xticks([])
    ax.set_yticks([])
    return(ax)
In [4]:
fig = plt.figure(figsize = (3*pi, 3.9))  
ax = fig.add_subplot(xlim = (-pi, pi),
                     ylim = (-1.3, 1.3))

ax.set_title("Ratio of Center of Mass in High Jump", fontsize = 24)

#Remove axes and ticks.
ax = clearAx(ax)
font1 = {'size' : 16}
font2 = {'size' : 20}

#Fifteen artists:
#circle, center, r1, r2, r3, blockout,
#phi left, phi right, phi value, a/b ratio
#a, b, a line, b line, center of mass line

circ = mpC((0,0),
           radius = 1,
           edgecolor = body,
           facecolor = "#FFFFFF",
           lw = 2,
           zorder = 1)

center = mpC((0, 0),
             radius = 0.05,
             edgecolor = dot,
             facecolor = dot,
             lw = 2,
             zorder = 3) 

r1 = mpL(xy = [(0, 0), (0, -1)],
         edgecolor = dot,
         facecolor = dot,
         ls = ':',
         lw = 1,
         zorder = 3)

r2 = mpL(xy = [(0, 0), (0, -1)],
         edgecolor = dot,
         facecolor = dot,
         ls = ':',
         lw = 1,
         zorder = 3)

r3 = mpL(xy = [(0, -1), (0, 0)],
         edgecolor = dot,
         facecolor = dot,
         ls = ':',
         lw = 1,
         zorder = 3)

rect = mpR((-pi, -2.1),
           height = 1,
           width = 2*pi,
           edgecolor = "#FFFFFF",
           facecolor = "#FFFFFF",
           lw = 1,
           zorder = 2)

phi_l = ax.text(0, 0, '', c = dot, ha = 'right', va = 'bottom', **font1)
phi_r = ax.text(0, 0, '', c = dot, ha = 'left', va = 'bottom', **font1)

phi = ax.text(pi-0.65, -0.82, '', c = 'k', ha = 'left', **font2)
ratio = ax.text(pi-0.65, -1.17, '', c = "k", ha = 'left', **font2)

#Ratio Details.
a_l = mpL(xy = [(-pi+0.1, -1), (0, -1)],
          edgecolor = dot,
          facecolor = dot,
          ls = ':',
          lw = 1,
          zorder = 3) 
com_l = mpL(xy = [(-pi+0.1, 0), (0, 0)],
            edgecolor = dot,
            facecolor = dot,
            ls = ':',
            lw = 1,
            zorder = 3)
b_l = mpL(xy = [(-pi+0.1, 1), (0, 1)],
          edgecolor = dot,
          facecolor = dot,
          ls = ':',
          lw = 1,
          zorder = 3) 
a_text = ax.text(-pi+0.1, -0.5, '', c = dot, ha = 'center', va = 'center', **font1)
b_text = ax.text(-pi+0.1, 0.5, '', c = dot, ha = 'center', va = 'center', **font1)


def init():
    
    """Initialize fifteen artists."""
    ax.add_patch(circ)
    ax.add_patch(center)
    ax.add_patch(r1)
    ax.add_patch(r2)
    ax.add_patch(r3)
    ax.add_patch(rect)
    
    phi_l.set_text('ϕ')
    phi_r.set_text('ϕ')
    phi.set_text('')
    ratio.set_text('')
 
    ax.add_patch(a_l)
    ax.add_patch(com_l)
    ax.add_patch(b_l)
    a_text.set_text('a')
    b_text.set_text('b')


    return circ, center, r1, r2, r3, rect, phi_l, phi_r, phi, ratio, a_l, com_l, b_l, a_text, b_text

def animate(i):

    if i < 360 :
        t = 180 - i/2
        tr = pi*t/180
        r = 180 / t
        c = (0, 1-r)
        x = r*sin(tr)
        y = r*cos(tr)+1-r
        phi_text = str(t)
    #Emphasize the final result.    
    else :
        t = 0
        tr = 0
        r = 10000
        c = (0, -9999)
        x = pi
        y = 1
        phi_text = '0'   
    
    #Arc is always 2𝜋, top of circle is always (0,1).
    circ.set_radius(r)
    circ.set_center(c)
    
    #Center.
    #Average out full semicircle above and circle sections below.
    if i < 180 :
        com = pi*(r-1)/2 - r*sin(tr)*cos(tr)/2 - r + 1 
        ans =  (com-y) / (1-com)
    #Circle section above only.    
    elif i < 360 :
        com = pi / (2*sin(tr)) + r*cos(tr)/2 - r + 1
        ans = (com-y) / (1-com)
    #Emphasize the final result.
    else :
        com = 1
        ans = 2
    
    ratio_text = str(round(ans, 4))
    center.set_center((0, com))
            
    #Radii
    r1.set_xy([c, (x, y)])
    r2.set_xy([c, (-x, y)])
    r3.set_xy([(0, 1), c])
    
    #Blockout.
    rect.set_height(y+2.09)
    
    #Where is ϕ?
    if i < 202 :
        phi_l.set_x(0.2)
        phi_l.set_y(c[1]+0.1)
        phi_r.set_x(-0.2)
        phi_r.set_y(c[1]+0.1)
    else :
        phi_l.set_y(-1.2)
        phi_r.set_y(-1.2)
        
        if i < 360 :
            trace = (pi-0.4)*(i-202)/(158*2)+0.2
            phi_l.set_x(trace)
            phi_r.set_x(-trace)
        else :
            phi_l.set_x(pi/2)
            phi_r.set_x(-pi/2)    
    
    #Info.
    phi.set_text("ϕ : " + phi_text + "°")
    ratio.set_text("a/b : " + ratio_text)
    
    #Ratio info.
    a_l.set_xy([(-pi+0.1, y), (x, y)])
    com_l.set_xy([(-pi+0.1, com), (0, com)])
    a_text.set_y((y+com)/2)
    b_text.set_y((1+com)/2)
    
    return circ, center, r1, r2, rect, phi_l, phi_r, phi, ratio, a_l, com_l, b_l, a_text, b_text

#Run animation.
anim = FA(fig, animate, init_func = init, frames = 400, interval = 25, blit = True)       

#Save animation.
anim.save('2024.08.16 EC.mp4');
Rohan Lewis¶

2024.08.19¶