Skip to content

Instantly share code, notes, and snippets.

@kaleidawave
Last active December 15, 2023 20:48
Show Gist options
  • Save kaleidawave/bdaf8649e7917152b6cdd624636344f9 to your computer and use it in GitHub Desktop.
Save kaleidawave/bdaf8649e7917152b6cdd624636344f9 to your computer and use it in GitHub Desktop.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
ax.set_aspect("equal", adjustable="box")
(path,) = ax.plot([], [], marker="o", color="r", linewidth=1, markersize=0.2)
centres = ax.scatter([], [], marker="o", color="b", linewidth=0.1)
def square(t):
p = t / (2 * np.pi) # normalise to p in (0, 1)
# Draw square between (0, 0), (1, 0), (0, 1), (1, 1)
relative = 4 * p
if relative < 1:
result = relative + 1j
elif relative < 2:
result = 1 + (2 - relative) * 1j
elif relative < 3:
result = 3 - relative
else:
result = (relative - 3) * 1j
# Scale and translate
return result * 2 - (1 + 1j)
interval = np.linspace(0, 2 * np.pi, 200)
def calculate_fourier_coefficints(interval, function, N=30):
"""Calculates `N` (complex) fourier coefficients for a function"""
coefficients = []
function = np.vectorize(function)
for n in range(-N, N):
res = function(interval) * np.exp(-n * 1j * interval)
cn = np.trapz(res) / (2 * np.pi)
coefficients.append(cn)
return coefficients
coefficients = calculate_fourier_coefficints(interval, square)
# Sort by size. Larger radiuses are drawn first
sorted_coeficients = sorted(
list(enumerate(coefficients, start=-(len(coefficients) // 2))), key=lambda x: np.abs(x[1]), reverse=True
)
circles = [plt.Circle((0, 0), np.abs(c), color="g", fill=False) for (_, c) in sorted_coeficients]
for circle in circles:
ax.add_patch(circle)
x_data, y_data = [], []
def update(t):
x, y = 0, 0
# v = my_function(t)
# x, y = np.real(v), np.imag(v)
centeres = []
centeres.append((x, y))
for i, (omega, c) in enumerate(sorted_coeficients):
circles[i].set_center((x, y))
p = c * np.exp(omega * 1j * t)
x += np.real(p)
y += np.imag(p)
centeres.append((x, y))
centres.set_offsets(centeres)
# Final result of summation
x_data.append(x)
y_data.append(y)
path.set_data(x_data, y_data)
return [path, centres, *circles]
vp = 50
ax.set_xlim(-vp, vp)
ax.set_ylim(-vp, vp)
animation = FuncAnimation(fig, update, frames=interval, interval=50, blit=True)
plt.get_current_fig_manager().window.showMaximized()
plt.show()
# paused = False
# def toggle_pause(_):
# global paused
# if paused:
# animation.resume()
# else:
# animation.pause()
# paused = not paused
# from matplotlib.widgets import Button
# axes = plt.axes([0, 0, 0.2, 0.2])
# Button(axes, "Play/Pause", color="yellow")
# bnext.on_clicked(toggle_pause)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment