Setup¶

In [1]:
import math
import matplotlib
from matplotlib.animation import FuncAnimation as FA
from matplotlib.patches import Polygon as mpP
import matplotlib.pyplot as plt
import numpy as np

Constants and Helpers¶

In [2]:
#Rectangle corners.
c = [(-2, -1), (-2, 1), (2, 1), (2, -1)]



#Frostings
f = ['#2A788EFF', '#2A788E66',
     '#440154FF', '#44015466',
     '#7AD151FF', '#7AD15166']



#Polygon pieces of cake.
def polygonPiece(points, edgecolor, facecolor, lw, zo):
    
    return(mpP(points,
               edgecolor = edgecolor,
               facecolor = facecolor,
               lw = lw,
               zorder = zo))



#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)



######For Amimation######

#x in terms of z
def X(z):
    x = (-15*z**2 + 150*z) / (3*z**2 - 30*z + 300)
    return(x)


#y in terms of x
def Y(x):
    y = math.sqrt((-3*x + 5) * (x + 5))/3
    return(y)

zs = [z/20 for z in range(101)]
xs = [X(z) for z in zs]
ys = [Y(x)/5 for x in xs]
xs = [x/5 for x in xs]

#4 quadrants
xs = xs + list(reversed(xs[0:100]))
xs = xs + [-x for x in xs[1:201]]

ys = ys + [-y for y in reversed(ys[0:100])]
ys = ys + list(reversed(ys[0:200]))

#All (x,y)
centers = [i for i in zip(xs, ys)]
zs = [z/100 for z in range(401)]

#All end of cuts along perimeter.
ends = []
for z in zs:
    if z <= 2 :
        ends.append([(-2, -1+z),
                     (0+z, 1),
                     (2-z, -1)])
    else :
        ends.append([(-2+z-2, 1),
                     (2, 1-z+2),
                     (0-z+2, -1)])
In [3]:
def cakeCuts(c, f, option) :
    
    fig = plt.figure(figsize = (10, 5))
    ax = fig.add_subplot(xlim = (-2.02, 2.02),
                         ylim = (-1.01, 1.01))
    ax = clearAx(ax)

    if option == 1:
        
        center = (0, 1/3)
        #Ends of 3 cuts.
        es = [c[0], (0, 1), c[3]]

        #3 Polygon pieces of cake.
        piece1 = polygonPiece([c[0], center, c[3], c[0]], f[0], f[1], 3, 1)
        piece2 = polygonPiece([c[0], c[1], es[1], center, c[0]], f[2], f[3], 3, 1)
        piece3 = polygonPiece([center, es[1], c[2], c[3], center], f[4], f[5], 3, 1)
       
    if option == 2:
        
        center = (1/3, 0)
        #Ends of 3 cuts.
        es = [(-2, 0), (1, 1), (1, -1)]
        
        #3 Polygon pieces of cake.
        piece1 = polygonPiece([c[0], es[0], center, es[2], c[0]], f[0], f[1], 3, 1)
        piece2 = polygonPiece([es[0], c[1], es[1], center, es[0]], f[2], f[3], 3, 1)
        piece3 = polygonPiece([es[2], center, es[1], c[2], c[3], es[2]], f[4], f[5], 3, 1)


    if option == 3:
        
        center = (1/10, 1/math.sqrt(75))
        #Ends of 3 cuts.
        es = [(-2, -.5), (.5, 1), (1.5, -1)]

        #3 Polygon pieces of cake.
        piece1 = polygonPiece([c[0], es[0], center, es[2], c[0]], f[0], f[1], 3, 1)
        piece2 = polygonPiece([es[0], c[0], c[1], es[1], center, es[0]], f[2], f[3], 3, 1)
        piece3 = polygonPiece([es[2], center, es[1], c[2], c[3], es[2]], f[4], f[5], 3, 1)
        
        #Origin.
        plt.scatter(0, 0, c = 'k', lw = 7, zorder = 3)
        #New Center.    
        plt.scatter(center[0], center[1], c = 'grey', lw = 7, zorder = 3)
        
        #Horizontal & Vertical
        plt.plot([-1.99, 1.99],
                 [center[1], center[1]],
                 'grey',
                 lw = 2,
                 ls = '--',
                 zorder = 2)
        
        plt.plot([center[0], center[0]],
                 [-0.99, 0.99],
                 'grey',
                 lw = 2,
                 ls = '--',
                 zorder = 2)
        
        text = [#Regions
            ("A1", (-0.6, -0.65), f[0], 36, 0),
            ("A2", (0.45, -0.65), f[0], 36, 0),
            ("B1", (center[0], 0.65), f[2], 36, 0),
            ("B2", (-1.65, -0.1), f[2], 36, 0),
            ("C1", (1.3, 0.5), f[4], 36, 0),
            ("C2", (1.3, -0.5), f[4], 36, 0),

  
            #Around the perimeter.
            ("z", (-1.92, -0.75), 'k', 28, 90),
            ("5+y-z", (-1.92, (-0.5+center[1])/2), 'k', 14, 90),
            ("5-y", (-1.92, (1+center[1])/2), 'k', 14, 90),
            
            ("10+x", ((-2+center[0])/2, 0.92), 'k', 14, 0),
            ("z", ((0.5+center[0])/2-0.06, 0.92), 'k', 28, 0),
            ("-x", ((0.5+center[0])/2+0.03, 0.92), 'k', 14, 0),
            ("10-z", (1.25, 0.92), 'k', 14, 0),
            
            ("5-y", (1.92, (1+center[1])/2), 'k', 14, 270),
            ("5+y", (1.92, (-1+center[1])/2), 'k', 14, 270),
            
            ("z", (1.75, -.92), 'k', 28, 0),
            ("10-x-z", ((1.5+center[0])/2, -.92), 'k', 14, 0),
            ("10+x", ((-2+center[0])/2, -.92), 'k', 14, 0),
        
            #Origin & Center.
            ("(0, 0)", (-0.3, -0.2), 'k', 28, 0),
            ("(x, y)", (center[0]+0.4, center[1]+0.15), 'gray', 28, 0),]

    if option == 4:
        
        ax = fig.add_subplot(xlim = (0, .505),
                             ylim = (0, 0.2525))

        clearAx(ax)
        
        #Points.
        plt.scatter(0, 5/30, c = 'k', lw = 7, zorder = 3)
        plt.scatter(5/30, 0, c = 'k', lw = 7, zorder = 3)
        
        center = (1/10, 1/math.sqrt(75))
        #Ends of 3 cuts.
        es = [(-2, -.5), (.5, 1), (1.5, -1)]

        #3 Polygon pieces of cake.
        piece1 = polygonPiece([c[0], es[0], center, es[2], c[0]], None, f[1], 3, 1)
        piece2 = polygonPiece([es[0], c[0], c[1], es[1], center, es[0]], None, f[3], 3, 1)
        piece3 = polygonPiece([es[2], center, es[1], c[2], c[3], es[2]], None, f[5], 3, 1)
     
        #All Centers!
        xs = [x/30 for x in range(51)]
        ys = np.divide([math.sqrt((-3*x+5)*(x+5))/3 for x in xs], 10)
        xs = np.divide(xs, 10)
        centers = polygonPiece([i for i in zip(xs, ys)] + [(0,0)] + [(xs[0], ys[0])], 'k', '#00000066', 3, 2)
        
        #Text
        text = [("(0, 5/3)", (0.05, 0.19), 'k', 28, 0),
                ("(5/3, 0)", (0.22, 0.01), 'k', 28, 0),]
        
    ax.add_patch(piece1)
    ax.add_patch(piece2)
    ax.add_patch(piece3)
    
    if option != 4 :
        #Slices are black.
        for p in es :
            plt.plot([p[0], center[0]],
                     [p[1], center[1]],
                     c = 'k',
                     lw = 4,
                     zorder = 2)       
       
    if option == 3 or option == 4:
        #Pow.
        for t in text :
            plt.annotate(text = t[0],
                         xy = t[1],
                         c = t[2],
                         size = t[3],
                         ha = "center",
                         va = "center",
                         rotation = t[4],
                         zorder = 2)
    if option == 4 :
        ax.add_patch(centers) 
          
    fig.savefig("2024.03.01" + str(option) + ".png", bbox_inches = 'tight')
In [4]:
cakeCuts(c, f, 1)
In [5]:
cakeCuts(c, f, 2)
In [6]:
cakeCuts(c, f, 3)
In [7]:
cakeCuts(c, f, 4)
In [8]:
matplotlib.rc_file_defaults()

fig = plt.figure(figsize = (10, 5))
ax = fig.add_subplot(xlim = (-2.02, 2.02),
                     ylim = (-1.01, 1.01))

ax.set_title("Threeway Equal Area and Perimeter Division of Cake", fontsize = 24)

#Remove axes and ticks.
ax = clearAx(ax)

font = {'size' : 24}

#Twelve artists:
#Piece 1, Piece 2, Piece 3,
#Slice 1, Slice 2, Slice 3,
#z1, z2, z3.
#Center Shape,
#z
#(x, y)


p1 = polygonPiece([c[0], centers[0], c[3], c[0]], f[0], f[1], 3, 1)
p2 = polygonPiece([c[0], c[1], (0,1), centers[0], c[0]], f[2], f[3], 3, 1)
p3 = polygonPiece([centers[0], (0,1), c[2], c[3], centers[0]], f[4], f[5], 3, 1)

s1 = polygonPiece([c[0], centers[0]], 'k', 'k', 4, 2)
s2 = polygonPiece([(0,1), centers[0]], 'k', 'k', 4, 2)
s3 = polygonPiece([c[3], centers[0]], 'k', 'k', 4, 2)

z1 = polygonPiece([c[0], ends[0][0]], 'gray', 'gray', 5, 3)
z2 = polygonPiece([(0, 1), ends[0][1]], 'gray', 'gray', 5, 3)
z3 = polygonPiece([c[3], ends[0][2]], 'gray', 'gray', 5, 3)

center_sh = polygonPiece([centers[0]], 'k', '#00000000', 4, 2)

z_text = ax.text(0, -1.18, '', c = 'gray', ha = 'center', **font)
xy_text = ax.text(0, 0.66, '', ha = 'center', **font)

def init():
    """Initialize seven artists."""
    ax.add_patch(p1)
    ax.add_patch(p2)
    ax.add_patch(p3)
    
    ax.add_patch(s1)
    ax.add_patch(s2)
    ax.add_patch(s3)
    
    ax.add_patch(z1)
    ax.add_patch(z2)
    ax.add_patch(z3)
    
    ax.add_patch(center_sh)
    
    z_text.set_text('')
    xy_text.set_text('')
    
    return p1, p2, p3, s1, s2, s3, z1, z2, z3, center_sh, z_text, xy_text

def animate(i):

    z = zs[i]
    x = xs[i]
    y = ys[i]
    center = centers[i]
    end = ends[i]
    
    """Update nine artists."""
    if z <= 2 :
        p1.set_xy([c[0], end[0], center, end[2], c[0]])
        p2.set_xy([end[0], c[1], end[1], center, end[0]])
        p3.set_xy([center, end[1], c[2], c[3], end[2], center])
        
        z1.set_xy([c[0], end[0]])
        z2.set_xy([(0, 1), end[1]])

    else :
        p1.set_xy([c[0], c[1], end[0], center, end[2], c[0]])
        p2.set_xy([center, end[0], c[2], end[1], center])
        p3.set_xy([end[2], center, end[1], c[3], end[2]])
        
        z1.set_xy([c[0], c[1], end[0], c[1]])
        z2.set_xy([(0, 1), c[2], end[1], c[2]])
    
    z3.set_xy([c[3], end[2]])
    
    s1.set_xy([end[0], center])
    s2.set_xy([end[1], center])
    s3.set_xy([end[2], center])

    if i < 399:
        center_sh.set_xy(centers[0:(i+1)]+ list(reversed(centers[0:(i+1)])))
    else:
        center_sh.set_xy(centers[0:(i+1)])
        center_sh.set_facecolor('k')

    z_text.set_text("z = %.2f" % (z*5))
    xy_text.set_text("(x, y) = (%.2f, %.2f)" %(center[0]*5, center[1]*5))

    return p1, p2, p3, s1, s2, s3, z1, z2, z3, center_sh, z_text, xy_text

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

#Save animation.
anim.save('2024.03.01 EC.mp4');

Rohan Lewis¶

2024.03.04¶