import math
from math import ceil as mC
from math import floor as mF
from math import sqrt as mS
import matplotlib
from matplotlib import colormaps as cm
import matplotlib.colors as colors
from matplotlib.patches import Polygon as mpP
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
#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)
#Diametric Beach.
#Return list of coordinates for matplotlib.
def drawDiametric(X) :
diam = []
for x in X:
diam.append(0)
return(diam)
#Semicircle Beach.
#Return list of coordinates for matplotlib.
def drawSemicircle(X) :
semi = []
for x in X:
semi.append(mS(1-x**2))
return(semi)
#Equidistant.
#Return list of coordinates for matplotlib.
def drawEquidistant(X) :
equi = []
for x in X:
equi.append((-x**2 + 1) / 2)
return(equi)
def createDistDF(X) :
df = pd.DataFrame(columns = ['X', 'Y', 'D'])
i = 0
for x in X :
for y in range(mF(250*mS(1-x**2))) :
y = y/250
#Assume Semicircular Beach is closer.
d = 1 - mS(x**2+y**2)
#If Diametric is, then switch.
if y < d :
d = y
df.loc[i] = [x, y, d]
i += 1
return(df)
#Visual!
#Fiddler1 - Annotation.
#Fiddler2 - Areas.
#EC1 - Annotation.
#EC2 - Heatmap!
def beachPic(o, length) :
fig = plt.figure(figsize = (length, 6))
ax = fig.add_subplot(xlim = (-1.17, 1.17),
ylim = (-0.234, 1.17))
fig.subplots_adjust(left = 0.02, bottom = 0.02, right = 0.98, top = 0.98)
X = [x/250 for x in range(-250, 251, 1)]
diam = drawDiametric(X)
semi = drawSemicircle(X)
equi = drawEquidistant(X)
#Remove axes and ticks.
ax = clearAx(ax)
border = 'k'
#Algebra & Geometry.
if o == 'Fiddler1' or o == 'EC1' :
if o == 'Fiddler1' :
labels = ["(x, y) ", " (x, 0) ", "1-√(x²+y²)", "√(x²+y²)", "y", "x"]
else :
labels = ["(rcosθ, rsinθ) ", " (rcosθ, 0) ", "1-r", "r", "rsinθ", "rcosθ"]
#Equidistant.
#ax.plot(X, equi,
#color = 'grey', lw = 1, ls = ':', zorder = 1)
ax.plot([-1/2, 0, -3/8, -3/8],
[mS(3)/2, 0, 0, mS(27)/8],
color = 'k', lw = 2, ls = ':', zorder = 2)
ax.scatter([-1/2, 0, -3/8, -3/8],
[mS(3)/2, 0, 0, mS(27)/8],
color = 'grey', lw = 8, zorder = 4)
text = [(labels[0], (-3/8, mS(27)/8), 'grey', 14, 'right', 'top', 0),
(labels[1], (-3/8, -0.02), 'grey', 14, 'center', 'top', 0),
(" (0, 0) ", (0, -0.02), 'grey', 14, 'center', 'top', 0),
(labels[2], (-7/16+0.05, mS(147)/16+0.05), 'k', 20, 'center', 'center', 300),
(labels[3], (-3/16+0.05, mS(27)/16+0.05), 'k', 20, 'center', 'center', 300),
(labels[4], (-3/8-0.05, mS(27)/16), 'k', 20, 'center', 'center', 90),
(labels[5], (-3/16, 0.05), 'k', 20, 'center', 'center', 0)]
for t in text :
plt.annotate(text = t[0],
xy = t[1],
c = t[2],
size = t[3],
ha = t[4],
va = t[5],
rotation = t[6],
zorder = 4)
#Area plot.
elif o == 'Fiddler2' :
xy_semi = list(zip(X, semi)) + [(-1, 0)]
ax.add_patch(mpP(xy_semi, ec = 'k', fc = 'k', zorder = 1))
ax
xy_diam = list(zip(X, equi)) + [(-1, 0)]
ax.add_patch(mpP(xy_diam, ec = 'w', fc = 'w', zorder = 2))
text = [("π/2 - 2/3", (0, 0.75), 'w'),
("2/3", (0, 0.25), 'k')]
for t in text :
plt.annotate(text = t[0],
xy = t[1],
c = t[2],
size = 50,
ha = 'center',
va = 'center',
zorder = 4)
#Heatmap.
elif o == 'EC2' :
df = createDistDF(X)
heatmap = plt.scatter(x = df['X'],
y = df['Y'],
c = df['D'],
cmap = 'viridis_r',
marker = "s",
s = 3,
vmin = 0,
vmax = 0.5)
#Colorbar.
cb = plt.colorbar(heatmap)
ticks = [0, 0.1, 0.2, 0.3, 0.4, 0.5]
cb.set_ticks(ticks)
cb.set_label('Shortest Distance to Shore',
labelpad = -80,
fontsize = 20)
cb.ax.tick_params(labelsize = 16)
plt.annotate(text = "Average Shortest Distance = 1/3-4/9π ≈ 0.1919",
xy = (0, -0.15),
c = cm['viridis'](0.6162),
size = 25,
ha = 'center',
va = 'center',
zorder = 4)
border = '#FDE725FF'
#Diametric Beach.
ax.plot(X, diam, color = border, lw = 3, zorder = 3)
#Semicircle Beach.
ax.plot(X, semi, color = border, lw = 3, zorder = 3)
fig.savefig("2025.03.14" + o + ".png", bbox_inches = "tight")
beachPic("Fiddler1", 10)
beachPic("Fiddler2", 10)
beachPic("EC1", 10)
beachPic("EC2", 12)