9.5 动画 在MATLAB中有三种用于动画的工具:
comet和comet3函数可以用来绘制彗星图,正如我们在第7章中简要提到的那样。 getframe函数可用于从一系列图形生成“电影帧”。然后可以使用movie函数来播放指定次数的电影。 最通用的(和令人满意的)创建动画的方法是使用Handle Graphics工具。下面是两个例子。 9.5.1 带有手柄图形(Handle Graphics)的动画 对于初学者,运行以下脚本,它应该显示跟踪正弦曲线的标记,并在其后面留下一条轨迹:
% animated sine graph x = 0 ; y = 0 ; dx = pi /40 ; p = plot (x, y, 'o' , 'EraseMode' , 'none' ); % 'xor' shows only current point % ' none' shows all points axis([0 20 *pi -2 2 ])for x = dx:dx:20 *pi ; x = x + dx; y = sin (x); set(p, 'XData' , x, 'YData' , y) drawnowend
在代码中,语句p = plot(x, y, 'o', 'EraseMode', 'none');
实现了几个功能。具体解释如下:
绘制第一个数据点:使用plot()
函数绘制了第一个数据点。'o'
表示使用圆圈标记绘制数据点。此时,此语句绘制了具有初始坐标(x, y)的点,并将其显示在画布上。
保存绘图句柄:通过将plot()
函数的返回值赋值给变量p,我们保存了该绘图对象的句柄。句柄是一个指向图形对象的引用,可以用来在后续的操作中引用和修改图形对象。
设置EraseMode属性:使用'EraseMode'
参数将EraseMode属性设置为'none'
。EraseMode属性用于控制图形对象的绘制方式。通过将其设置为'none'
,在图形对象绘制时不会对其进行擦除。这意味着每次重新绘制图形对象时,它将保留在画布上,而不被擦除。
要实现完整的动画效果,可以尝试将EraseMode属性设置为'xor'
。在这种情况下,每次重新绘制图形对象时,它会以稍微不同的位置被擦除,从而创造出经典的动画效果。
通过将EraseMode属性设置为'xor'
,每次重新绘制图形对象时,之前的图形对象将被擦除,并以略微不同的位置重新绘制。这将产生动画效果,图形对象似乎在画布上移动或变化。
在代码中的语句set(p, 'XData', x, 'YData', y)
用于将对象p的x和y数据值设置为在迭代循环中生成的新值,并重新绘制该对象。然而,这并不意味着它会立即在屏幕上绘制出来,而是加入了"事件队列",等待被执行。
set()
函数:set()
函数用于设置对象的属性值。在这里,我们使用它来更新对象p的属性值。
对象p:对象p是之前通过plot()
函数创建的图形对象。我们通过保存其句柄,即使用变量p引用该对象。
属性的设置:使用set()
函数,我们通过指定属性名称和新的数值,将对象p的属性值进行更新。在这个语句中,属性名称是'XData'和'YData',即x和y数据。通过将x和y的新值分别传递给这两个属性,我们将更新对象的数据。
重新绘制对象:一旦对象的属性值被设置为新值,对象将被重新绘制。这意味着对象将以新的数据值在画布上显示出来。
事件队列:然而,更新后的对象不会立即在画布上绘制出来。它被添加到所谓的"事件队列"中。事件队列是一个缓冲区,用于存储未处理的绘图事件。
刷新事件队列:要将对象从事件队列中刷新出来并在画布上绘制,需要调用drawnow
函数。drawnow
函数用于执行等待中的绘图事件并刷新图形,并将其显示在画布上。
通过将对象的属性值设置为新值并调用drawnow
函数,可以使更新的对象立即显示在画布上。这样,可以在每次迭代中更新对象的位置,并使用drawnow
函数刷新事件队列以实时显示绘图。这样,就可以完成动态图形的连续绘制和更新。
根据help drawnow
的说明,有四种事件可以刷新事件队列:
回到MATLAB提示符:当回到MATLAB提示符时,绘图事件队列将刷新,并将绘图对象显示在画布上。这是您在之前绘制的所有图形中看到的方式。
暂停语句:当执行到暂停语句时,绘图事件队列将刷新,并将绘图对象显示在画布上。暂停语句可以在代码中指定等待的时间,以便观察和分析图形。
执行getframe
命令:当执行getframe
命令时,绘图事件队列将刷新,并将绘图对象显示在画布上。getframe
命令用于捕获当前的图形帧,并将其存储为帧数据。
执行drawnow
命令:当执行drawnow
命令时,绘图事件队列将立即刷新,并将绘图对象显示在画布上。drawnow
命令用于强制刷新事件队列,并立即显示图形更新。
例如,您可以使用pause(0.05)
替换drawnow
来使标记以更慢的速度移动,即每0.05秒更新一次。pause(0.05)
函数将在每次迭代之间添加一个短暂的时间延迟,以控制更新的速度。
洛伦兹奇异吸引子下一个例子是基于MATLAB文档中的动画部分中的一个示例。它涉及到由三个非线性微分方程描述的混沌运动,这个系统被称为洛伦兹奇异吸引子(Lorenz strange attractor)。
洛伦兹吸引子是由爱德华·洛伦兹 (Edward Lorenz) 在1963年发现的一种非线性动力学系统。它是一个具有混沌特性的系统,描述了大气科学和流体力学中的对流现象。其微分方程的形式如下:
在这里,、 和 是系统的状态变量, 是时间,σ 、 ρ 和 β 是常数。通过选择适当的初始条件和参数值,可以生成漂亮的混沌运动动画。
系统可以写成:
式中, 是一个有三个分量的向量, 是一个关于 的矩阵:
这个脚本使用欧拉法(Euler's method)对系统进行近似求解(更准确的数值解法在第17章中讨论),并展示了解在两个不同的吸引子周围轨道运动的情况,而不会停留在一个稳定轨道上。在绘制了数千个点之后,下图展示了这种情况。
A = [ -8 /3 0 0 ; 0 -10 10 ; 0 28 -1 ]; y = [35 -10 -7 ]'; h = 0.01 ; p = plot3 (y(1 ), y(2 ), y(3 ), 'o' , ...'erasemode' , 'none' , 'markersize' , 2 );axis([0 50 -25 25 -25 25 ])hold oni = 1 ;while 1 A(1 ,3 ) = y(2 ); A(3 ,1 ) = -y(2 ); ydot = A*y; y=y+h*ydot;% Change color occasionally if rem (i ,500 ) == 0 set(p, 'color' , [rand , rand , rand ])end % Change co-ordinates set(p, 'XData' , y(1 ), 'YData' , y(2 ), 'ZData' , y(3 )) drawnowi =i +1 ;end %%警告: EraseMode 属性不再受支持,而且在以后的版本中会出错。 %%警告: EraseMode 属性不再受支持,而且在以后的版本中会出错。 %%2014后的版本EraseMode 属性不再受支持,而且在以后的版本中会出错。
如果所有的点都以相同的颜色绘制,你最终将无法看到生成的新点:屏幕的大片区域将被绘制的颜色填充。因此,每绘制500个点后,颜色是随机设置的。
在较新的版本中,"erasemode" 属性已不再受支持,并且在将来的版本中会产生错误。
如果你想要清除图形并绘制新的数据点,你可以使用 "clf" 命令来清除当前图形窗口,并使用 "plot3" 命令重新绘制数据点。
下面是更新后的代码示例:
A = [ -8 /3 0 0 ; 0 -10 10 ; 0 28 -1 ]; y = [35 -10 -7 ]'; h = 0.01 ; p = plot3 (y(1 ), y(2 ), y(3 ), 'o' , 'markersize' , 2 ); axis([0 50 -25 25 -25 25 ])hold oni = 1 ;while 1 A(1 ,3 ) = y(2 ); A(3 ,1 ) = -y(2 ); ydot = A*y; y = y + h*ydot; % Change color occasionally if rem (i ,500 ) == 0 set(p, 'color' , [rand , rand , rand ]) end % Change co-ordinates set(p, 'XData' , y(1 ), 'YData' , y(2 ), 'ZData' , y(3 )) drawnow i = i + 1 ;end
请注意,"erasemode" 属性的移除可能会导致绘图过程中的一些变化。