import math
from math import pi as pi
from math import sqrt as mS
import matplotlib
from matplotlib.patches import Circle as mpC
from matplotlib.patches import Polygon as mpP
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
#Colors.
C = ['#440154FF', '#3B528BFF', '#21908DFF', '#5EC962FF', '#FDE725FF']
#Angles
ts = [0, pi/3, 2*pi/3, pi, 4*pi/3, 5*pi/3, 2*pi]
#Clear axes.
def clearAx(ax):
"""
Clear the axes in the plot.
Parameters:
ax : Current ax.
Returns:
ax : After being cleared.
"""
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)
#Bubble.
def drawBubble(ax, xy, c, a, o) :
"""
Draw a bubble, which is a unit circle.
Parameters:
ax : Current ax.
xy : Center, (x, y).
c : Bubble color.
a : Alpha level.
o : Option.
If it is 'Fiddler', it is simply a colored bubble.
If it is 'EC', three petals are drawn.
Returns:
None.
However, patches are drawn.
"""
if o == 'Fiddler' :
lw = 2
else :
lw = 0
#Bubble.
ax.add_patch(mpC(xy = xy,
radius = 1,
edgecolor = 'k',
facecolor = c,
alpha = a,
lw = lw,
zorder = 1))
#Three Petals.
if o == 'EC' :
#Center
x = xy[0]
y = xy[1]
#Bottom.
ax.add_patch(drawPetal([xy, (x, y-mS(3))],
[ts[4], ts[1]],
[ts[5], ts[2]],
C[0],
'full'))
#Right.
ax.add_patch(drawPetal([(x-1/2, y - mS(3)/2), (x+1, y)],
[ts[0], ts[3]],
[ts[1], ts[4]],
C[0],
'full'))
#Left.
ax.add_patch(drawPetal([(x+1/2, y - mS(3)/2), (x-1, y)],
[ts[2], ts[5]],
[ts[3], ts[6]],
C[0],
'full'))
#Petals.
def drawPetal(centers, theta0, theta1, c, o):
"""
Draw a half or full petal, traced from 1/6 of an arc of a bubble.
Parameters:
centers : [(x0, y0), *(x1, y1)]
theta0 :[t00, *t01]
theta1 :[t10, *t11]
c : Petal color.
o : Option.
If it is 'half', it is a half petal.
If it is 'full', it is a full petal. If it is full, the optional * values above are used.
Returns:
None.
However, patches are drawn.
"""
#Half petal.
x0, y0 = centers[0]
#Create a list of angles between theta1 and theta2
a0 = np.linspace(theta0[0], theta1[0], 30)
#Compute the (x, y) points on the unit circle
points = [(x0 + np.cos(t), y0 + np.sin(t)) for t in a0]
#Add second half of petal.
if o == 'full' :
x1, y1 = centers[1]
# Create a list of angles between theta1 and theta2
a1 = np.linspace(theta0[1], theta1[1], 30)
#Compute the (x, y) points on the unit circle
points += [(x1 + np.cos(t), y1 + np.sin(t)) for t in a1]
return(mpP(xy = points,
edgecolor = None,
facecolor = c,
lw = 0,
zorder = 2))
def bubblePlot(o, so) :
"""
Output the bubbles.
Parameters:
o, so : Option, suboption.
Returns:
None.
However, plot is shown.
"""
sns.set()
#Plot.
fig = plt.figure(figsize = (9, 9))
ax = fig.add_subplot(xlim = (-2, 2), ylim = (-2, 2))
clearAx(ax)
if o == 'Fiddler' :
#Hexafoil.
if so == '1' :
#Bubble.
drawBubble(ax, [1,0], 'None', 1, o)
drawBubble(ax, [1/2, -mS(3)/2], 'None', 1, o)
drawBubble(ax, [-1/2, -mS(3)/2], 'None', 1, o)
drawBubble(ax, [-1,0], 'None', 1, o)
drawBubble(ax, [-1/2, mS(3)/2], 'None', 1, o)
drawBubble(ax, [1/2, mS(3)/2], 'None', 1, o)
drawBubble(ax, [0,0], 'None', 1, o)
#Math.
elif so == '2' :
ax = fig.add_subplot(xlim = (-1, 1), ylim = (-1, 1))
clearAx(ax)
#Bubble.
drawBubble(ax, [0,0], C[4], 1, o)
#Top.
ax.add_patch(drawPetal([[0,0]], [ts[0]], [ts[3]], C[2], 'half'))
#Petal formed from far left bubble overlap.
#ax.add_patch(drawPetal([[0, 0], [-3/2, -mS(3)/2]], [ts[3], ts[0]], [ts[4], ts[1]], C[1], 'full'))
#Petals formed from bottom left bubble overlap.
ax.add_patch(drawPetal([[-1/2, -mS(3)/2]], [ts[0]], [ts[1]], C[0], 'half'))
ax.add_patch(drawPetal([[-1/2, -mS(3)/2], [-1/2, mS(3)/2]], [ts[1], ts[4]], [ts[2], ts[5]], C[0], 'full'))
#Petals formed from bottom right bubble overlap.
ax.add_patch(drawPetal([[1/2, -mS(3)/2], [1/2, mS(3)/2]], [ts[1], ts[4]], [ts[2], ts[5]], C[0], 'full'))
ax.add_patch(drawPetal([[1/2, -mS(3)/2]], [ts[2]], [ts[3]], C[0], 'half'))
#Petal formed from far right bubble overlap.
#ax.add_patch(drawPetal([[0, 0], [3/2, -mS(3)/2]], [ts[5], ts[2]], [ts[6], ts[3]], C[1], 'full'))
#1/6 sector.
ax.add_patch(drawPetal([[0, 0]], [ts[4]], [ts[5]], C[1], 'half'))
ax.add_patch(mpP([(0,0), (1/2, -mS(3)/2), (-1/2, -mS(3)/2), (0,0)], ec = C[1], fc = C[1], alpha = 1, zorder = 2))
#Dotted Lines.
ax.plot([-1, 1], [0, 0], C[4], ls = ':', zorder = 3 )
ax.plot([-1/2, 1/2], [-mS(3)/2, -mS(3)/2], C[4], ls = ':', zorder = 3 )
#Final Image.
elif so == '3' :
#Outer 6 bubbles.
drawBubble(ax, [1,0], C[2], 1, o)
drawBubble(ax, [1/2, -mS(3)/2], C[2], 1, o)
drawBubble(ax, [-1/2, -mS(3)/2], C[2], 1, o)
drawBubble(ax, [-1,0], C[2], 1, o)
drawBubble(ax, [-1/2, mS(3)/2], C[2], 1, o)
drawBubble(ax, [1/2, mS(3)/2], C[2], 1, o)
#Erase overlap.
points = [(1/2 + np.cos(t), mS(3)/2 + np.sin(t)) for t in np.linspace(ts[5], ts[6], 50)]
x,y = zip(*points[1:-1])
ax.plot(x, y, c = C[2], lw = 3)
#Add overlap.
points = [(1 + np.cos(t), np.sin(t)) for t in np.linspace(ts[1], ts[2], 50)]
x,y = zip(*points)
ax.plot(x, y, c = 'k', lw = 2)
#Draw center bubble.
drawBubble(ax, [0,0], C[4], 1, 'Fiddler')
#All petals.
ax.add_patch(drawPetal([[-1/2, -mS(3)/2], [-1/2, mS(3)/2]], [ts[1], ts[4]], [ts[2], ts[5]], C[0], 'full'))
ax.add_patch(drawPetal([[-1, 0], [1/2, mS(3)/2]], [ts[0], ts[3]], [ts[1], ts[4]], C[0], 'full'))
ax.add_patch(drawPetal([[-1/2, mS(3)/2], [1, 0]], [ts[5], ts[2]], [ts[6], ts[3]], C[0], 'full'))
ax.add_patch(drawPetal([[1/2, mS(3)/2], [1/2, -mS(3)/2]], [ts[4], ts[1]], [ts[5], ts[2]], C[0], 'full'))
ax.add_patch(drawPetal([[1, 0], [-1/2, -mS(3)/2]], [ts[3], ts[0]], [ts[4], ts[1]], C[0], 'full'))
ax.add_patch(drawPetal([[1/2, -mS(3)/2], [-1, 0]], [ts[2], ts[5]], [ts[3], ts[6]], C[0], 'full'))
#Extra Credit Lattice.
else :
#Circle types.
for xs in [range(-2, 3),
[-5/2, -3/2, -1/2, 1/2, 3/2, 5/2]] :
#Center x.
for x in xs :
#Center y.
for y in [mS(3)*i for i in xs] :
#Draw bubble with 3 petals.
drawBubble(ax, [x,y], C[4], 1, o)
fig.savefig('2025.06.06' + o + so +'.png', bbox_inches = "tight");
bubblePlot('Fiddler', '1')
bubblePlot('Fiddler', '2')
bubblePlot('Fiddler', '3')
bubblePlot('EC', '')