我想做的是使用 Matplotlib 绘制轨道模拟的数据;下面附有我想要实现的目标的示例。
我有行星以及航天器相对于太阳的 X、Y、Z、时间坐标的数据(或者如果需要,我可以重新运行以获取其他坐标系中的数据)。
如何制作这样的 GIF?
我尝试只使用 x,y 的 pyplot,但我只得到一个平面图像,而不是移动的 GIF。(正如预期的那样,因为 PyPlot 只能制作静态图)。非常感谢任何帮助/指向我可以查看的地方。
matplotlib FuncAnimation
工具根据 matplotlib 中的数据创建动画。这个想法是将动画视为帧的集合,并根据帧编号定义每个帧的图形/内容(假设帧按升序放置)。有关 matplotlib 动画的更多详细信息可以在官方网站的此页面上找到:Matplotlib Animations。答案的其余部分专门针对该问题提供了一些指导。
这是我使用 matplotlib
FuncAnimation
创建的虚拟动画。它基于问题的想法(尽管使用虚拟数据)。
这是生成上述动画的代码 -
from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import math
# dummy parameters, replace them with your own
sun_x, sun_y = 0, 0
voyager1_theta, voyager1_speed, voyager1_radius = 0, 0.003*math.pi, 40
planet1_theta, planet1_speed, planet1_radius = 0, 0.002*math.pi, 40
planet2_theta, planet2_speed, planet2_radius = 0, 0.001*math.pi, 90
fps = 10 # frames per second in animation
total_time = 5 # in seconds, total time of animation
time_ratio = 100 # in seconds, how many seconds in reality for every second on animation
# extra calculations
interval = 1/fps # in seconds
total_frames = total_time * fps
voyager_x_data = []
voyager_y_data = []
fig, ax = plt.subplots()
def update(frame):
# this function accepts the frame-number as frame and creates the figure for it
global ax
# dummy calculations, replace them with your own calculations
time = frame*interval*time_ratio # in seconds
voyager_x = (voyager1_radius+time/20) * math.cos(voyager1_speed*time + voyager1_theta)
voyager_y = (voyager1_radius+time/20) * math.sin(voyager1_speed*time + voyager1_theta)
voyager_x_data.append(voyager_x)
voyager_y_data.append(voyager_y)
planet1_x = planet1_radius * math.cos(planet1_speed*time + planet1_theta)
planet1_y = planet1_radius * math.sin(planet1_speed*time + planet1_theta)
planet2_x = planet2_radius * math.cos(planet2_speed*time + planet2_theta)
planet2_y = planet2_radius * math.sin(planet2_speed*time + planet2_theta)
# plotting
ax.clear() # clear the figure (to remove the contents of last frame)
ax.set_ylim(-100,100)
ax.set_xlim(-100,100)
ax.set_aspect('equal')
ax.set_title('Time = {:.3f} sec'.format(time))
ax.scatter(sun_x, sun_y, color = 'yellow', marker = 'o') #, label='Sun')
ax.scatter(planet1_x, planet1_y, color = 'blue', marker = 'o') #, label = 'Planet1')
ax.scatter(planet2_x, planet2_y, color = 'green', marker = 'o') #, label = 'Planet2')
ax.plot(voyager_x_data, voyager_y_data, color = 'red')
ax.scatter(voyager_x, voyager_y, color = 'red', label = 'Voyager')
ax.legend()
anim = FuncAnimation(fig, update, frames = range(total_frames), interval = interval*1000) # multiplying by 1000 to convert sec into milli-sec
anim.save('result.gif', fps = fps) # replace the name of file with your own path and name
#plt.show() # uncomment this line and comment out the second-last line to see in realtime instead of saving
代码内的注释包含阅读和使用代码时所需的所有辅助信息。本节包含整体说明。
fps
、total_time
、time_ratio
。fig, ax = plt.subplots()
),然后定义 update
函数,该函数将帧号作为输入并为该帧号创建图形。FuncAnimation
创建动画。在代码中,我们使用 FuncAnimation(fig, update, frames = range(total_frames), interval = interval*1000)
来完成此操作。我们指定帧来匹配我们想要的时间,指定间隔来匹配我们想要的动画 FPS。plt.show()
。要保存,请调用 anim.save()
,在其中指定输出文件的路径以及文件名和 fps 以计算我们想要的 FPS。注意:
指定的文件名中的扩展名用于决定导出格式。在anim.save()
的帮助下支持其他格式。要获得对其他格式的支持,请安装ffmpeg
并在ffmpeg
中指定writer='ffmpeg'
。anim.save()