Reputation: 89
I'm trying to make this animation from wikipedia, however, I'm having a hard time figuring out how to do it. Basically I need to do two things:
this is the code I have, but I get ten different frames
import numpy as np
import matplotlib.pyplot as plt
R=3 #Biggest circle radius =3
r=1 #smallest circle radius =1
t=np.linspace(0, 2*np.pi,100) # values from zero to 360 degrees
i=0
xc1=R*np.cos(t) #biggest circle
yc1=R*np.sin(t) #biggest circle
plt.plot(xc1,yc1)
while i<=2*np.pi:
x=(R-r)*np.cos(i)+r*np.cos((R-r)*i/r) #x values of the hypocycloid
y=(R-r)*np.sin(i)-r*np.sin((R-r)*i/r)#y value of the hypocycloid
plt.plot(x,y)
i+=2*np.pi/10
plt.show()
Thank you very much in advance.
Upvotes: 0
Views: 1509
Reputation: 9810
Here a full example how to do it, using the equations given in the Wikipedia page the OP linked. As there are quite a few variables to be tracked, I thought it was best to collect everything in a class.
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
class Hypocycloid:
def __init__(self, ratio = 3, frames = 100, ncycles = 1):
self.frames = frames
self.ncycles = ncycles
self.fig, self.ax = plt.subplots()
self.ax.set_aspect('equal')
##big circle:
theta = np.linspace(0,2*np.pi,100)
x = np.cos(theta)
y = np.sin(theta)
self.big_circle, = self.ax.plot(x,y,'b-')
##small circle:
self.small_r = 1./ratio
r = self.small_r
x = r*np.cos(theta)+1-r
y = r*np.sin(theta)
self.small_circle, = self.ax.plot(x,y,'k-')
##line and dot:
self.line, = self.ax.plot([1-r,1],[0,0],'k-')
self.dot, = self.ax.plot([1-r],[0], 'ko', ms=5)
##hypocycloid:
self.hypocycloid, = self.ax.plot([],[],'r-')
self.animation = FuncAnimation(
self.fig, self.animate,
frames=self.frames*self.ncycles,
interval=50, blit=False,
repeat_delay=2000,
)
def update_small_circle(self, phi):
theta = np.linspace(0,2*np.pi,100)
x = self.small_r*np.cos(theta)+(1-self.small_r)*np.cos(phi)
y = self.small_r*np.sin(theta)+(1-self.small_r)*np.sin(phi)
self.small_circle.set_data(x,y)
def update_hypocycloid(self, phis):
r = self.small_r
x = (1-r)*np.cos(phis)+r*np.cos((1-r)/r*phis)
y = (1-r)*np.sin(phis)-r*np.sin((1-r)/r*phis)
self.hypocycloid.set_data(x,y)
center = [(1-r)*np.cos(phis[-1]), (1-r)*np.sin(phis[-1])]
self.line.set_data([center[0],x[-1]],[center[1],y[-1]])
self.dot.set_data([center[0]], [center[1]])
def animate(self, frame):
frame = frame+1
phi = 2*np.pi*frame/self.frames
self.update_small_circle(phi)
self.update_hypocycloid(np.linspace(0,phi,frame))
hypo = Hypocycloid(ratio=3.25, frames = 40, ncycles=4)
##un-comment the next line, if you want to save the animation as gif:
##hypo.animation.save('hypocycloid.gif', writer='imagemagick', fps=10, dpi=75)
plt.show()
The parameters that you can pass to the Hypocycloid
class are ratio
(radius of the small circle relative to the big one), frames
(number of frames for one trip of the small circle around the big circle), and ncycles
(number of trips). The final result for ratio=3.25
, frames=40
, and ncycles=4
looks like this:
Upvotes: 2