python制作动态图形--摆线篇

python制作动态图形--摆线篇

首先展示效果图

摆线动画


如何实现

通过python的第三方库的matplotlib.的matplotlib.animation功能就能够轻松实现

并且这个过程只始于两行代码

import matplotlib.animation as animation
ani = animation.FuncAnimation(fig, update, frames=range(len(points)), init_func=init, interval=1)

简而言之,实现原理就是每次update函数每播放一帧动画就跟新一次函数。(FuncAnimation更多参数大家可以查阅官网)

摆线

摆线定义:在数学中,摆线(Cycloid)被定义为,一个圆在一条直线上滚动时,圆边界上一定点所形成的轨迹。 它是一般旋轮线的一种。 摆线亦称圆滚线。

摆线方程

x = r*(t-sint)

y = r*(1-cost)

摆线图形(也是我用matplotlib绘制的图形,代码我附在完整代码中了,很简单,大家感兴趣的化可以看看)

摆线图像


第一步:了解我们需要的参数

让我们回到最开始的图形,可以看到动画由什么组成

line, = ax.plot([], [], 'o-', color='g', lw=1)  # 圆心连线 @center -> curve
circle, = ax.plot([], [], '-', color='b', lw=1)  # 滚动的圆
cycloid, = ax.plot([], [], '-', color='r', lw=1)  # 摆线
cycloid_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)  # 显示摆线此时得出坐标
cycloid_x, cycloid_y = [], [] # 摆线x,y坐标的集合

第二步:初始化对象

初始化figure和其他对象,我们的所有操作都是在figure对象上进行的。举例来说,类似于你在纸上绘画,用铅笔添加数据,用橡皮擦除数据。

fig = plt.figure(figsize=(8, 2)) # 初始化figure对象
ax = plt.gca() # 在figure添加一个图
ax.grid() # 在图上添加网格线
ax.set_ylabel('y label') # 在图上为y轴添加注释
ax.set_title("cycloid animation") # 为图形设置标题
line, = ax.plot([], [], 'o-', color='g', lw=1)  # 初始化圆心连线对象
circle, = ax.plot([], [], '-', color='b', lw=1)  # 初始化滚动的圆对象
cycloid, = ax.plot([], [], '-', color='r', lw=1)  # 初始化摆线对象
cycloid_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)  # 初始化文本对象(显示摆线此时得出坐标)

# 以下是绘制图形所需的数据
cycloid_x, cycloid_y = [], [] # 摆线数据的集合
r = 1 # 圆的半径
t = np.linspace(0, np.pi * 2, 1000)
length = 4 * np.pi * r # update的数据源(即t的范围是0-8*pi


第三步:设置init__fuct函数

这步的作用是为图像设置框架,使图像看起来更加美观

def init():
   ax.set_xlim(-r, length + r) # 设置x轴的范围
   ax.set_ylim(0, 2 * r + 1)   #设置y轴的范围
   line.set_data([0, 0], [0, 1]) # 开始时,圆心和摆线的连线
   x_out = r * np.cos(t) # 圆上每一点的x轴坐标
   y_out = r * np.sin(t) + r # 圆上每一点的x轴坐标
   circle.set_data(x_out, y_out) # 开始时,圆的图形
   return circle, line, # 返回圆和连线的数据

记住,line后必须有逗号,否则会出错

第四步:设置update函数

这一步是为每一帧动画更新数据,从而达到动态演示的效果

def update(frame):
   tt = points[frame]  # 获取参数t(见摆线方程)
   x = r * (tt - np.sin(tt)) # 获取摆线上该点的坐标
   y = r * (1 - np.cos(tt))
   cycloid_x.append(x)  # 添加摆线坐标
   cycloid_y.append(y)  
   cycloid.set_data(cycloid_x, cycloid_y)  # 更新摆线
   cycloid_text.set_text("(x, y):({},{})".format(round(x, 2), round(y, 2)))

   if len(cycloid_x) == len(points): # 当摆线的数据与t的长度相同时(也是一轮动画结束时),删除摆线
       cycloid_x.clear()
       cycloid_y.clear()

   # 更新圆的位置
   x_out = r * np.cos(t) + tt
   y_out = r * np.sin(t) + r
   circle.set_data(x_out, y_out)
   # 更新圆心和摆线连线
   line.set_data([tt, x], [r, y])
   return cycloid, circle, line,

好了,到这里就基本大工告成了

第五步 绘制动画

ani = animation.FuncAnimation(fig, update, frames=range(len(points)), init_func=init, interval=1)
# ani.save('rol.gif', writer='imagemagick', fps=60) # 保存图像为gif图,需要安装imagemagic软件,否则会报错
plt.show()

怎么样,大家是不是觉得很简单呢,动手试一试吧

完整代码

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


def cycloid_plot(r=1, start=0, end=2 * np.pi, num=100, style='b'):
   """
  功能:绘制摆线的图形
  公式:x=r[t-sin(t)], y=r[1-cos(t)]
  变量:
      r:半径
      start:t的起始位置
      end:t的终止位置
      num:选取的点的个数
      style:图形的样式
  """
   t = np.linspace(start, end, num)
   x = r * (t - np.sin(t))
   y = r * (1 - np.cos(t))

   fig, ax = plt.subplots()
   ax.plot(x, y, style, label="cycloid")
   ax.grid()
   ax.axis('equal')
   ax.set_xlabel('x label')
   ax.set_ylabel('y label')
   ax.set_title("cycloid")
   ax.legend()
   plt.show()


def cycloid_animation():
   # 摆线的演示动画
   fig = plt.figure(figsize=(8, 2))
   ax = plt.gca()
   ax.grid()
   ax.set_ylabel('y label')
   ax.set_title("cycloid animation")
   line, = ax.plot([], [], 'o-', color='g', lw=1)  # 圆心连线
   circle, = ax.plot([], [], '-', color='b', lw=1)  # 滚动的圆
   cycloid, = ax.plot([], [], '-', color='r', lw=1)  # 摆线
   cycloid_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)  # 显示摆线此时得出坐标
   cycloid_x, cycloid_y = [], []
   r = 1
   t = np.linspace(0, np.pi * 2, 1000)
   length = 4 * np.pi * r
   points = np.linspace(0, length, 250)

   def init():
       ax.set_xlim(-r, length + r)
       ax.set_ylim(0, 2 * r + 1)
       line.set_data([0, 0], [0, 1])
       x_out = r * np.cos(t)
       y_out = r * np.sin(t) + r
       circle.set_data(x_out, y_out)
       return circle, line,

   def update(frame):
       tt = points[frame]  # 获取参数t
       x = r * (tt - np.sin(tt))
       y = r * (1 - np.cos(tt))
       cycloid_x.append(x)
       cycloid_y.append(y)
       cycloid.set_data(cycloid_x, cycloid_y)  # 更新摆线
       cycloid_text.set_text("(x, y):({},{})".format(round(x, 2), round(y, 2)))

       if len(cycloid_x) == len(points):
           cycloid_x.clear()
           cycloid_y.clear()

       # update circle
       x_out = r * np.cos(t) + tt
       y_out = r * np.sin(t) + r
       circle.set_data(x_out, y_out)
       # new circle center @(tt,r)
       line.set_data([tt, x], [r, y])
       return cycloid, circle, line,

   ani = animation.FuncAnimation(fig, update, frames=range(len(points)), init_func=init, interval=1)
   # ani.save('rol.gif', writer='imagemagick', fps=60)
   plt.show()


if __name__ == '__main__':
   cycloid_plot()


本文为我原创

本文禁止转载或摘编

-- --
  • 投诉或建议
评论