Как анимировать на графике matplotlib - PullRequest
1 голос
/ 25 марта 2019

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

Я пытался использовать FuncAnimation (), но понятия не имею, как это работает. Я все еще новичок в Python, так что будь осторожен со мной, спасибо.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

A = np.array([-0.5,-0.5,-0.5])
B = np.array([0.5,-0.5,-0.5])
C = np.array([0.5,0.5,-0.5])
D = np.array([-0.5,0.5,-0.5])
E = np.array([-0.5,-0.5,0.5])
F = np.array([0.5,-0.5,0.5])
G = np.array([0.5,0.5,0.5])
H = np.array([-0.5,0.5,0.5])

load = np.array([A,B,C,D,E,F,G,H])
print(load)

fig = plt.figure()
ax = plt.axes(xlim =(-1,1),ylim =(-1,1))

#   Declared to allow for x and y axis only
projection = np.array([ [1,0,0], [0,1,0] ])
xdata,ydata = [],[]

plt.title("Render 3D Cube in 2D Space")
for x in load:
    for angle in range(360):
        rotationY = np.array([ [np.cos(angle),0,np.sin(angle)],
                        [0,1,0],
                        [-np.sin(angle),0,np.cos(angle)] ])
        rotationX = np.array([ [1,0,0],
                        [0,np.cos(angle),-np.sin(angle)],
                        [0,np.sin(angle),np.cos(angle)] ])

        #   Drawing each points
        rotated = np.dot(rotationY,x)
        rotated = np.dot(rotationX,rotated)
        projected2d = np.dot(projection,rotated)
        #projected2d = np.dot(projection,x) -With no rotations
    line = ax.plot(projected2d[0],projected2d[1],c = "blue",marker = "o")
def animate(i):
    x0,y0 = i
    xdata.append(x0)
    ydata.append(y0)
    line.set_data(xdata,ydata)
    return line
anim = FuncAnimation(fig,animate,interval =200,frames = 30)

plt.grid()
#plt.draw()
plt.show()

https://imgur.com/LR6oPtt

1 Ответ

1 голос
/ 26 марта 2019

Конструктор FuncAnimation принимает вызываемую функцию (в вашем случае animate), которая получает номер текущего кадра в качестве аргумента (здесь i) и обновляет график. Это означает, что вы должны хранить все свои промежуточные точки в массиве (frames), а затем обращаться к ним позже (вы также можете вычислить проекцию на лету, но я бы не рекомендовал это). Затем анимация будет проходить по кадрам и применять функцию к каждому кадру.

Кроме того, вы должны использовать радианы (углы от 0 до 2π) для ваших вращений.

Вот версия, которая должна работать:

# list of the angles in radians
angles = np.linspace(0, 2*np.pi, 360)

# storage of single frames - one value per point and angle.
frames = np.zeros((len(load),len(angles),2))

# loops through all points and angles to store for later usage.
for i, x in enumerate(load):
    for j, angle in enumerate(angles):
        rotationY = np.array([[np.cos(angle),0,np.sin(angle)],
                        [0,1,0],
                        [-np.sin(angle),0,np.cos(angle)] ])
        rotationX = np.array([ [1,0,0],
                        [0,np.cos(angle),-np.sin(angle)],
                        [0,np.sin(angle),np.cos(angle)] ])

        rotated = np.dot(rotationY, x)
        rotated = np.dot(rotationX, rotated)
        projected2d = np.dot(projection, rotated)

        # store the point.
        frames[i,j,:] = projected2d

# draws the initial point.
line, = ax.plot(frames[:,0,0], frames[:,0,1], c="blue", marker="o", ls='')


# defines what happens at frame 'i' - you want to update with the current
# frame that we have stored before.
def animate(i):
    line.set_data(frames[:,i,0], frames[:,i,1])
    return line # not really necessary, but optional for blit algorithm

# the number of frames is the number of angles that we wanted.
anim = FuncAnimation(fig, animate, interval=200, frames=len(angles))
...