гипоциклоидная анимация матплотлиб - питон - PullRequest
0 голосов
/ 12 октября 2018

Я пытаюсь сделать эту анимацию из Википедии, однако мне трудно понять, как это сделать.По сути, мне нужно сделать две вещи:

  1. Построить все графики в одном кадре.
  2. Построить самый большой круг и сохранить его, а затем нанести наименьший круг и точки гипоциклоиды,Однако мне также нужно сохранить точки гипоциклоиды и обновить положение наименьшего круга.

это код, который у меня есть, но я получаю десять разных кадров

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

Большое спасибо заранее.

1 Ответ

0 голосов
/ 13 октября 2018

Вот полный пример того, как это сделать, используя уравнения, приведенные на странице Википедии, на которую ссылается ОП.Поскольку существует довольно много переменных, которые нужно отслеживать, я подумал, что лучше всего собрать все в классе.

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

Параметры, которые вы можете передать классу Hypocycloid, равны ratio (radiusмалого круга относительно большого), frames (количество кадров за одну поездку малого круга вокруг большого круга) и ncycles (количество поездок).Окончательный результат для ratio=3.25, frames=40 и ncycles=4 выглядит следующим образом:

result of above code

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...