python动态画函数曲线_详解如何使⽤Python绘制动图(⼀)
解析FuncAnimat。。。
在这篇⽂章中,我们将熟悉并使⽤Matplotlib提供的animation模块,绘制动态图像。
我们将绘制⼀个简单的例⼦:在正弦函数上移动的切线。
⽂章⽬录
⼀. FuncAnimation接⼝与绘图思路
1. FuncAnimation接⼝
2. 绘图思路
(1). 绘制初始的静态图形
(2). 在func函数中更新数据以获得动态效果
(3). 调⽤FuncAnimation接⼝
⼆. 实践:绘制正弦曲线上变化的切线与切点
三. 完整代码
⼀. FuncAnimation接⼝与绘图思路
1. FuncAnimation接⼝
FuncAnimation是Matplotlib库为我们提供的⽤于绘制动态图像的接⼝,其中包含如下参数:
fig:画布对象,由创建画布时的返回得到,即fig = plt.figure()
frames:指定动图的帧数,但这个参数类型必须是可迭代的列表等。每次调⽤func函数对图像进⾏更新时,接⼝将⾃动向func函数提供此时的帧数num,这使得更新数据⼗分⽅便。
func:⽤于更新图⽚从⽽产⽣动态效果的调⽤函数,在编写时通常会⽤到set_data等类似的⽅法,其返回值是⼀个元素为被更新的图形对象的列表。同时,func可以接受帧数参数num,⽤来更新每帧图像。具体内容我们将在⽰例中看到。
interval:更新频率,单位是毫秒。
上⾯这些参数的⽤法我们会在具体的实践中更清楚的看到。
2. 绘图思路
(1). 绘制初始的静态图形
在绘制动态效果前,我们需要⼀个初始的静态的图⽚,例如在绘制正弦函数上变化的切线时,我们的初始图⽚是⼀条正弦函数曲线、在曲线第⼀个点上的切线以及对应的切点。在后续的动图中,切点与切线是变化的,也就是说,我们需要操作切点与切线这两个对象。
我们使⽤plot接⼝来绘制初始的正弦曲线、切点与切线,⽽实现后续的动态效果时,我们只需要更新绘制切点与切线时的数据即可。这就告诉我们,我们需要得到切点与切线的对象:
crave_ani = plt.plot(x,y,'red',alpha=0.5)[0]#正弦曲线
tangent_ani = plt.plot(xs,ys,c='blue',alpha=0.8)[0]#切线
point_ani = plt.plot(0,0,'r',alpha=0.4,marker='o')[0]#切点
(由于这只是⽰例,我们先不需要搞清楚绘制切线的数据是怎么得到的。)
我们⽤crave_ani、tanget_ani和point_ani这三个变量来表⽰从plot接⼝中返回的三个对象。值得注意的是,plot接⼝可以同时绘制多个对象(例如两条曲线同时绘制时),所以它的返回是⼀个列表,⽽我们需要使⽤列表的⽅式来获得其中的元素。这也是其它⽂章中出现这种写法的原因:
crave_ani, = plt.plot(x,y,'red',alpha=0.5)
在crave_ani后加⼀个逗号,实际上就是⽤来从plot接⼝返回的列表中获得第⼀个元素。
(2). 在func函数中更新数据以获得动态效果
当我们使⽤plot接⼝绘制了多个图形后,我们需要从中选择需要更新数据的图形。在我们的例⼦中,切线和切点是需要更新的,⽽我们已经有了代表它们的变量。这时,我们只需要在func函数中使⽤set_data⽅法,例如
point_ani.set_data(x[num],y[num])
在上⾯这句代码中,num是实时的帧数,我们在使⽤FuncAnimation接⼝时,这个参数是⾃动返回给func函数的。列表x和y则是我们提前计算的坐标值。我们只需要使⽤set_data⽅法即可快速的通过帧数来更新切点的数据。
在func函数中,我们需要将被更新的图形对象以诸如列表等可迭代的数据形式返回,例如
return [point_ani]
这句代码表⽰我们在func函数中更新了⼀个图形对象的数据,我们需要把它们组成列表返回。在其它⽂章中,可能出现这样的写法:
return point_ani,
这种写法实际上是将被改变的图形对象作为元组返回,总之,返回值必须是可迭代的。
(3). 调⽤FuncAnimation接⼝
在完成初始图像绘制并在func函数中实现数据更新后,我们调⽤FuncAnimation接⼝即可。例如
ani = animation.FuncAnimation(fig=fig,func=updata,frames=np.arange(0,100),interval=100)
需要注意的是,帧数的指定⼀定需要使⽤可迭代的数据类型。
在完成这些⼯作后,我们可以进⾏保存、展⽰等操作:
ani.save('sin_x.gif')
plt.show()
⼆. 实践:绘制正弦曲线上变化的切线与切点
⾸先,我们调⼊需要的模块。numpy模块为我们提供快捷的矩阵计算,⽽matplotlib库中的pyplot模块和animation模块则分别提供静态与动态图形的绘制⽅法:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
之后,我们对画布进⾏初始化:
fig = plt.figure()
完成画布的简单初始化后,我们开始绘制初始图形。⾸先是⼀条正弦曲线:
x = np.linspace(0,2*np.pi,100)
y = np.sin(x)
crave_ani = plt.plot(x,y,'red',alpha=0.5)[0]
之后绘制切点:
point_ani = plt.plot(0,0,'r',alpha=0.4,marker='o')[0]
为了使得动图效果更好,我们在画布上增加坐标值以及切线斜率的⽂字标识,这些标识也将是动态的:
xtext_ani = (5,0.8,'',fontsize=12)
ytext_ani = (5,0.7,'',fontsize=12)
ktext_ani = (5,0.6,'',fontsize=12)
最后,我们来绘制切线的斜率,这⾥我们⽤到了⼏个函数。⾸先是通过顶点与斜率计算整条切线的函数,这个函数计算定点附近的切线上的值,⽤来绘制切线:
def tangent_line(x0,y0,k):
xs = np.linspace(x0 - 0.5,x0 + 0.5,100)
ys = y0 + k * (xs - x0)
return xs,ys
之后我们还需要⼀个计算定点处切线斜率的函数,我们使⽤了简单的估计:
def slope(x0):
num_min = np.sin(x0 - 0.05)
num_max = np.sin(x0 + 0.05)
k = (num_max - num_min) / 0.1
return k
最后,调⽤这些函数和plot接⼝即可:
k = slope(x[0])
xs,ys = tangent_line(x[0],y[0],k)
tangent_ani = plt.plot(xs,ys,c='blue',alpha=0.8)[0]
此时,我们的初始图形绘制完成了,其效果是这样的:
下⾯,我们开始写⽤来更新数据的func函数:
def updata(num):
k=slope(x[num])
xs,ys = tangent_line(x[num],y[num],k)
tangent_ani.set_data(xs,ys)
point_ani.set_data(x[num],y[num])
xtext_ani.set_text('x=%.3f'%x[num])
ytext_ani.set_text('y=%.3f'%y[num])
ktext_ani.set_text('k=%.3f'%k)
return [point_ani,xtext_ani,ytext_ani,tangent_ani,k]
其中,我们利⽤set_data和set_text⽅法来更新切线、切点以及⽂字内容,⽽这些数据都通过帧数num与计算得到的坐标值挂钩。熟练的使⽤set_data⽅法使我们的func函数形式优美。
最后,我们只需调⽤FuncAnimation接⼝即可获得动态效果:
ani = animation.FuncAnimation(fig=fig,func=updata,frames=np.arange(0,100),interval=100) ani.save('sin_x.gif')
plt.show()
效果如下:
三. 完整代码
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
#初始化画布
fig = plt.figure()
#绘制⼀条正弦函数曲线
x = np.linspace(0,2*np.pi,100)
y = np.sin(x)
crave_ani = plt.plot(x,y,'red',alpha=0.5)[0]linspace函数python
#绘制曲线上的切点
point_ani = plt.plot(0,0,'r',alpha=0.4,marker='o')[0]
#绘制x、y的坐标标识
xtext_ani = (5,0.8,'',fontsize=12)
ytext_ani = (5,0.7,'',fontsize=12)
ktext_ani = (5,0.6,'',fontsize=12)
#计算切线的函数
def tangent_line(x0,y0,k):
xs = np.linspace(x0 - 0.5,x0 + 0.5,100)
ys = y0 + k * (xs - x0)
return xs,ys
#计算斜率的函数
def slope(x0):
num_min = np.sin(x0 - 0.05)
num_max = np.sin(x0 + 0.05)
k = (num_max - num_min) / 0.1
return k
#绘制切线
k = slope(x[0])
xs,ys = tangent_line(x[0],y[0],k)
tangent_ani = plt.plot(xs,ys,c='blue',alpha=0.8)[0]
#更新函数
def updata(num):
k=slope(x[num])
xs,ys = tangent_line(x[num],y[num],k)
tangent_ani.set_data(xs,ys)
point_ani.set_data(x[num],y[num])
xtext_ani.set_text('x=%.3f'%x[num])
ytext_ani.set_text('y=%.3f'%y[num])
ktext_ani.set_text('k=%.3f'%k)
return [point_ani,xtext_ani,ytext_ani,tangent_ani,k]
ani = animation.FuncAnimation(fig=fig,func=updata,frames=np.arange(0,100),interval=100) ani.save('sin_x.gif')
plt.show()
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论