Drawing Vertical Lines on a Plot Matlab
Goals
In this tutorial, you will learn how to create simple animation using basic MATLAB built-in function.
Conditions and Assumption
This tutorial was made based on MATLAB R2011b on Win7 64bit operating system. In this tutorial, it is assumed that you are using the same version of MATLAB and you have basic understanding and familiarity of MATLAB and its basic built-in functions (for the explanation of basic MATLAB's built-in function, see MATLAB's online documentation site). It is also assumed that you understand programming flow control such as conditional statements (switch–case andif–else) and loops (while andfor).
1. Concept of Creating Animation in MATLAB
Creating animation in MATLAB is fairly easy and simple. By using MATLAB's built-in function for plotting such as line, scatter, rectangle, etc, a simple animation can be made right away. There is no need to install additional toolboxes or download third-party m-files. In fact, several games in my MATLAB Fun Toolbox that I made, such as DoodleJump, Pong, and Congklak, uses only those built-in functions to create its animation.
Creating an animation in MATLAB is done by creating a plot and periodically updating it. The simplest way to do this is by using while loops. This while loop is usually preceded by some initialization; such as variable declaration and plot initialization. However, the loop itself must include of an updater (a code part that does the necessary calculation and updates the plot) and a pause command (which is needed to force MATLAB to refresh the plot). In most cases, an axis manipulation command must be included also inside the loop to maintain axis configuration throughout the animation. To understand this concept, see the example sinus wave animation script, Script01a, below.
%-------------------------------------------------------------------------- %Script01a - Dancing Sinus %Creating Simple Animation in MATLAB %MATLAB undercover %zerocrossraptor.wordpress.com %-------------------------------------------------------------------------- %This script m-file creates an endless animation of sinusoidal wave whose %amplitude keeps on changing between -1 and 1. %-------------------------------------------------------------------------- %CodeStart----------------------------------------------------------------- %Resetting MATLAB environment close all; clear all; clc; %Creating base plot (sinusoidal plot) x=0:10:360; y=sind(x); %Declaring variable as a scale factor (amplitude) for base plot theta=0; %Executing infinite loop to animate base plot while 1 %Scaling base plot theta=theta+1; y_plot=y*sind(theta); plot(x,y_plot); %Preserving axis configuration axis([0,360,-1.2,1.2]); %Delaying animation pause(0.001); end %CodeEnd-------------------------------------------------------------------
Script01a above generates an animation of sinusoidal wave with varying amplitude. This script uses endless while loop (line 21 to 31) to perform the animation. Thus, the script will continue endlessly until it is terminated by pressing ctrl+C. Even if the plot window is closed, MATLAB will create a new one and continue the animation. In this script, the while loop is preceded by an initialization that create basic plot of sine wave (line 17 and 18) and declares the initial value of theta (line 20), which will be used later inside the loop to modify the amplitude of the sine wave. The while loop itself consists of a simple calculation that is done to modify the amplitude of sine wave (line 23 to 25) and a command to create/update the plot (line 26). This part is the updater part. Beside the updater, axis command is also used to maintain axis configuration (line 28). This is done to prevent MATLAB from automatically adjusting the axis to fit the sine wave plot. Lastly, at the end of the loop content, pause command is added to force MATLAB to refresh the plot on the screen (line 30).
To understand more why axis command and pause command is necessary, try running Script01a above without either axis or pause command (use ctrl+R to comment out a line). If axis command is not used, the animation will be created with unfixed axis configuration because of MATLAB's automatic axis adjustment to fit the plot contents. This is usually undesired as this causes animation to change abruptly. On the other hand, if pause command is not used, no animation will be created. MATLAB command window will be blocked and shown that it is busy while no animation or even plot is generated until the script is terminated with ctrl+C. This happens because MATLAB prioritize calculations over graphical updates and will only execute graphical updates when there is no other tasks that need to be executed. Thus, when pause command is not used, MATLAB will suspend the plot and axis command in line 28 and line 30 and execute the next loop immediately. By addingpause command, MATLAB will suspend executing the next loop and executing the plot command instead as it has no task to execute during the waiting time. That's why, a pause is needed at the end of each loop. Note that the pause command can does not have to be put at the end of each loop. It can also be put at the beginning of each loop.
Beside pause command, drawnow command can also be used to force MATLAB to update the plot before moving on to the next loop. Usingdrawnow is very useful for quick code drafting; however, unfortunately it does not allow control over animation pace. With drawnow command, MATLAB will move on and execute the new loop right after the plot is updated. Unfortunately, the running time of one loop is untimed and will varies for each new loop although the content of the loop itself does not changed. Thus, when drawnow is used instead of pause, the animation will be played at inconsistent and uncontrollable pace. Eventually, to achieve constant and desired pace (for example, 20x refresh rate every one second),pause command must be used (See section 2 of this tutorial). Since both pause and drawnow command force MATLAB to update the plot, putting pause after drawnow renders the drawnow command itself to be unnecessary. Thus, unless consistent animation pace is not important, it is always a good practice to use pause instead of drawnow and control the animation speed.
2. Controlling Animation Speed and Creating Real-Timed Animation
As mentioned previously, while pause seems to be used only to 'trick' MATLAB into updating the plot, it actually serves as the clock/timer of the animation. The input argument for pause command determines how long MATLAB should wait before it executes the next loop. Thus, its value will become the time interval between the execution of two consecutive loops (plot updates). The smaller its value, the shorter the delay between two plot updates and the animation will be played faster, and vice versa. In gaming terms, the frequency of animation update is usually called refresh rate or frame rate and it is usually expressed in fps (frames per seconds). Simply speaking, the input argument of pause command dictates the animation pace. To make an animation runs well and smooth, an appropriate time interval / refresh rate must be chosen for pause command's input argument.
Before getting into how to choose the appropriate time interval, there is one problem related with pause command that should be addressed first. It should be noticed that pause command halt task execution between the end of one loop and the start of the next loop. Thus, time interval given as pause command's input argument is actually the time delay between the end of a loop with the start of the next loop, NOT the time delay between the starts of two consecutive loops. The real time interval between the starts of two consecutive loops is the pause time PLUS the time that MATLAB needs to run the content of the loop (This is usually called CPU time or CPU run time). Unfortunately, although the content of the loop does not change, its run time will always varies for each loop because of various reason; such as current PC load, variable size, etc. Thus, when a constant time interval value is used for pause command's input argument, the actual time interval between the start of two consecutive loops will not be constant, but varies due to the contribution of CPU run time.
The simplest way to enforce constant time interval between the start of two consecutive loops is to use tic and toc command to calculate the CPU run time and used it to alter the input argument for pause command. The following Script01b (Bouncing Ball Animation Script) shows the example of how to use tic and toc command to alter input argument for pause command. Basically, in the beginning of the loop, tic command is called to start the timer for CPU run time (line 35). At the end of the loop content, right before pause command is called, toc command is called to find out elapsed CPU run time since tic was called (line 56). Then, pause command is called with the desired time interval minus CPU run time as its input argument (line 58). By doing so, actual time interval between two consecutive loops is modified to be as close as possible with the desired value (which is dt in Script01b) regardless of the variation of CPU run time for each loop. Note that doing this does not guarantee that the time interval will always be exactly the same. However, it will suppress the run time fluctuation and yield more consistent animation pace.
%-------------------------------------------------------------------------- %Script01b - Bouncing Ball %Creating Simple Animation in MATLAB %MATLAB Undercover %zerocrossraptor.wordpress.com %-------------------------------------------------------------------------- %This script m-file creates an endless animation of bouncing balls. %-------------------------------------------------------------------------- %CodeStart----------------------------------------------------------------- %Resetting MATLAB environment close all; clear all; clc; %Declaring ball's initial condition initpos=50; %Ball's initial vertical position initvel=0; %Ball's initial vertical velocity %Declaring environmental variable r_ball=5; %Ball's radius gravity=10; %Gravity's acceleration c_bounce=1; %Bouncing's coefficient of elasticity %Declaring animation timestep dt=0.0125; %Animation timestep %Drawing first frame rectangle('Position',[-r_ball,initpos,r_ball,r_ball],... 'Curvature',[1,1],... 'FaceColor','b'); line([-5*r_ball,5*r_ball],... [0,0]); %Executing animation pos=initpos-r_ball; %Ball's current vertical position vel=initvel; %Ball's current vertical velocity while 1 %Declaring time counter t_loopstart=tic(); %Updating ball's condition pos=pos+(vel*dt); %Ball's current vertical position vel=vel-(gravity*dt); %Ball's current vertical velocity %Adjusting ball's velocity if the ball is hitting the floow if pos<0 vel=-vel*c_bounce; %Balls' current vertical velocity end %Clearing figure clf; %Drawing frame rectangle('Position',[-r_ball,pos,r_ball,r_ball],... 'Curvature',[1,1],... 'FaceColor','b'); line([-5*r_ball,5*r_ball],... [0,0]); %Preserving axes axis([-5*r_ball,5*r_ball,0,initpos+2*r_ball]); axis('equal'); axis('off'); %Pausing animation el_time=toc(t_loopstart); disp(['Elapse time : ',num2str(el_time),' seconds']); pause(dt-el_time); end %CodeEnd-------------------------------------------------------------------
Choosing the appropriate time interval is somewhat tricky. Basically, to make the animation run smoothly, time interval must be set as short as possible. However, since MATLAB itself also need some time to execute the content of the loop, the required CPU run time (to execute the content of the loop) should also be considered when choosing animation's time interval. If the desired time interval is shorter than the CPU run time, the animation will lag behind. While pause command will not return any error when negative value is given as its input (as the result of desired time interval – CPU run time), the animation refresh rate will be inconsistent because it is updated based on the inconsistent CPU run time. And if a real-timed animation is desired, the animation will lag behind.
Since human eyes refresh rate is somewhere around 18Hz or 20Hz, using 0.05s as animation time interval is a safe bet. This value is also long enough for MATLAB to execute the content of the loop for typical operation on typical computer specification. Nevertheless, shorter time interval is always desired to make the animation smoother. To determine shortest possible time interval, the variation of CPU run time should be estimated first. This is why in the bouncing ball animation 1, the elapsed CPU run time timed by tic and tac command is displayed. From this elapsed CPU run time, several time interval should be tried out to see whether the animation run smooth or not. As a quick rule of thumb, use twice the value of the CPU run time as the animation time interval and then gradually decrease it until the desired level of animation smoothness is achieved without causing lag. In Script01b's case, the elapsed CPU run time for one loop ranges from 0.008s to 0.01s. Time interval of 0.025s is used at first, and then tweaked into 0.0125s to make the animation smoother. Note that if the elapsed CPU run time for one loop is more than 0.05s, smooth animation may not be able to be achieved and perhaps the content of the loop should be modified/optimized/simplified to reduce the CPU run time.
Since time interval will be tweaked to determine its appropriate value, it is always a good practice to declare it as a variable and update everything based on this variable. In Script01b, the variable dt is used as the time interval for the animation and both the ball's position and velocity is calculated based on dt (line 37 and 38). By doing this, tweaking time interval can be easily done just by modifying the value of dt. Doing this also makes the animation normalized. It means that regardless of the animation time interval, the animation will always be played in same speed, only different refresh rate. For example, in Script01b, the ball is initially placed 50m above the ground without any velocity and it is being pulled down by gravity acceleration of 9.8m/s2. Using simple mathematics shown below, it can be calculated that the ball will reach the ground after roughly 3.2s. By normalizing the animation, the ball will always reach the ground after 3.2s of animation regardless of the animation's time interval.
Keep in mind that although normalizing the animation makes the animation theoretically unaffected by the selection of time interval, it does not guarantee uniform animation speed and appropriate time interval must still be determined. If the time interval is long, it will messed up the position and velocity calculation (line 37 and 38), while if it is too short, it will lag behind. To understand this more, try running Script01b with different values of dt.
3. Handling Figure for Animation
In Script01b, the animation was made by drawing initial circle with rectangle command and ground line with line command (line 24 to 29), clearing the old circle with clf command in each loop (line 44), and re-drawing new circle and ground line with the same rectangle and line command (line 45 to 59) in every loops. An endless while loop was used to run the animation (clearing the old plot and creating new one) over and over again. While this does the job well, it is not the most efficient way to make an animation, because MATLAB have to clear the previous plot from the screen, make new plot, and draw it to the screen again. Besides that, this code also runs infinitely until you terminate it manually with ctrl+C. Closing the figure will not stop the animation because MATLAB will create new figure and continue the loop normally. Simply speaking, there is no way to escape the endless loop and end Script01b without inducing an error.
To make the animation more efficient and provide an easy escape from the infinite loop, the figure object that hosts the animation must be handled manually instead of letting MATLAB automatically handles it. This can be done by creating a figure object and an axes object as the parent for the animation and appropriately assigning their properties. The following Script01c (Bouncing Ball Animation with Manual Figure Handling) shows how it is done. Note that Script01c does the exact same animation with the previous Script01b does. The only difference is that in this new script, figure object, axes object, and plot objects are handled manually.
%-------------------------------------------------------------------------- %Script01c - Bouncing Ball with Manual Figure Handling %Creating Simple Animation in MATLAB %MATLAB Undercover %zerocrossraptor.wordpress.com %-------------------------------------------------------------------------- %This script m-file creates an endless animation of bouncing balls with %manual figure handling. %-------------------------------------------------------------------------- %CodeStart----------------------------------------------------------------- %Resetting MATLAB environment close all; clear all; clc; %Declaring ball's initial condition initpos=50; %Ball's initial vertical position initvel=0; %Ball's initial vertical velocity %Declaring environmental variable r_ball=5; %Ball's radius gravity=10; %Gravity's acceleration c_bounce=1; %Bouncing's coefficient of elasticity %Declaring animation timestep dt=0.0125; %Animation timestep %Initiating figure, axes, and objects for animation fig=figure('DeleteFcn',@closefigfcn); axs=axes('Parent',fig); ball=rectangle('Position',[-r_ball,initpos,r_ball,r_ball],... 'Curvature',[1,1],... 'FaceColor','b',... 'Parent',axs); line([-5*r_ball,5*r_ball],... [0,0],... 'Parent',axs); %Executing animation pos=initpos-r_ball; %Ball's current vertical position vel=initvel; %Ball's current vertical velocity play=true; %Current animation status while play %Declaring time counter t_loopstart=tic(); %Updating ball's condition pos=pos+(vel*dt); %Ball's current vertical position vel=vel-(gravity*dt); %Ball's current vertical velocity if pos<0 vel=-vel*c_bounce; %Ball's current vertical velocity end %Updating ball set(ball,'Position',[-r_ball,pos,r_ball,r_ball]); %Preserving axes axis(axs,[-5*r_ball,5*r_ball,0,initpos+2*r_ball]); axis(axs,'equal'); axis(axs,'off'); %Pausing animation el_time=toc(t_loopstart); disp(['Elapse time : ',num2str(el_time),' seconds']); pause(dt-el_time); end %CodeEnd-------------------------------------------------------------------
Figure object is a MATLAB object that hosts other MATLAB objects such as uicontrol objects (buttons, edit box, slider, and normal text) and axes objects. Axes object is another MATLAB object that hosts MATLAB plot objects, such as line, rectangle, scatter, contour, etc. Figure object, axes object, and plot object form a parent-children relation. In short, plot object must be a children of axes object (plot must be hosted in an axes) while an axes object must be a children of figure object (axes must be hosted in a figure). Higher level object can have more than one children, for example, a figure can have more than one axes (which can be achieved easily with subplot command) and so does an axes (In bouncing ball animation 1, the axes have two plot objects in it: the rectangle object and the line object). However, the lower level object can only have one object as its parent.
In Script01b, a plot object for ball representation is created from rectangle function (line 25 to 27). Since this rectangle object must be hosted in an axes object and there is no available axes object to put these rectangle object, MATLAB automatically creates an axes object to host the rectangle object. Then, figure object is also automatically created to accommodate the axes object. After that, a line object for ground is created (line 28 to 29). Since there is an available axes from the previous one, the line object is put in this axes too, together with the rectangle object. Then, inside while loop, clf command is invoked to delete all existing object in the figure (line 44) followed by rectangle and line command (line 45 to 50) which will make MATLAB creates new rectangle and line object and put it in the existing figure (In the process, MATLAB also creates new axes object since clf command also deletes all axes objects).
In short, for every loop in Script01b, an axes object, a rectangle object, and a line object are deleted and then new ones are created. This is why the animation is not efficient. New objects have to be created in every loop just to be destroyed in the next loop. A more efficient way to do the animation is by re-using plot object and updating its property's value instead of deleting it and replacing it with a brand new one. This is what's done in Script01c.
In Script01c, a figure object and axes object is created first before creating any plot objects (line 25 to 26). Then, a rectangle object is created and assigned to ball variable (line 28 to 31). The rectangle object is assigned to a variable so that it enables the object to be accessed/modified by using this variable. Then, a line object is created (line 32 to 34). The line object is not assigned to a variable because it represent the ground and it's property will not be modified throughout the animation. Then, inside the loop, set function is invoked to modify the rectangle object's properties by using ball variable (line 49). This way, animation is more efficient and resulted in less CPU run time for one loop. Script01c takes roughly 0.006s of CPU run time for one loop, which is considerably faster than Script01b (0.008s to 0.01s). Notice also that in Script01c, the line object that represent ground is not redrawn in every loop.
Another difference that should be noticed in Script01c is that the figure object (line 26) is created with two input arguments and the main while loop uses play variable as its decision variable instead of 1. This is done on purpose to provide an escape from the endless loop. By using play variable as the decision variable for the main loop, the main loop can be stopped by changing the value of play variable to false, while creating figure object with DeleteFcn argument as shown in line 26 will assign a callback function called closefigfcn as a function that will be executed when the figure is closed/deleted. With this scheme, the play variable can be set to false from closefigfcn function, which is called when the figure is closed. Hence, the animation can be stopped simply by closing the fig figure.
To make this scheme work, closefigfcn function must be defined. Since Script01c is written as script, there is no other way but to define closefigfcn function by creating new m-files. The following shows the content of closefigfcn function written in separate m-file. Basically, this function only have two lines of code. The first one is assignin function (line 14) which is used to set the value of play variable to false and stops the animation. The other one is pause command (line 15). To set play variable to false, the conventional variable assignment (play = false;) can not be used because play variable is a workspace variable (variable that is created from script m-file) and it does not exist inside the scope ofclosefigfcn function. If the conventional variable assignment is used, MATLAB will create a new play variable which only exist inside the closefigfcn while the play variable in the workspace remain unchanged. This is whyassignin function is used, so that closefigfcncan access a variable that is out of its normal scope.
%-------------------------------------------------------------------------- %closefigfcn %Script01c - Bouncing Ball with Manual Figure Handling %Creating Simple Animation in MATLAB %MATLAB Undercover %zerocrossraptor.wordpress.com %-------------------------------------------------------------------------- %This function m-file was created as callback function to provide an escape %from endless while loop and stop animation in Script01c. %-------------------------------------------------------------------------- %CodeStart----------------------------------------------------------------- function closefigfcn(source,event) assignin('base','play',false); pause(1); end %CodeEnd-------------------------------------------------------------------
The second line in closefigfcn is pause command (line 15). The reason why pause command is added in closefigfcn is to prevent error due to figure deletion and unfinished loop. When play variable is set to false in line 14 of closefigfcn function, MATLAB does not stop the main loop right away. MATLAB will have to finish the entire loop that is currently running because the play variable is not re-checked until one complete loop is done. On the other hand, when closefigfcn execution is finished, MATLAB will delete fig figure right away, which will lead to the deletion of axs (axes object) and ball (rectangle object). The deletion of these objects will cause error when line 48 to 53 in Script01c are to be executed because these objects are no longer exist. Thus, to make sure MATLAB finishes up the last running loop before fig figure is deleted, pause command is used to delay the completion ofclosefigfcn function. This way, the animation can be automatically stopped when the figure is closed without creating any error.
4. Wrapping All the Necessities in One File
In Script01c, all necessary components for creating simple animation have been laid out along with the accompanyingclosefigfcn as the callback function. Unfortunately, script m-file is not the best way to create an animation because it may be affected by existing workspace variables and will clutter up MATLAB workspace with various variables that are used to run animation even after the animation is finished. While it can be solved by adding clear command at the start and end of the script, it is still not the elegant way to create an animation. Besides that, script m-file also does not allow local function as its content, thus forcing the callback function to be created in separate m-file. While it is agreed that separating each function in a separate m-file is a good coding practice (and I agree to some extent), it will make file management harder when Script01c wants to be moved as it must be moved together with closefigfcn or else it won't work. In this case,closefigfcn function is a specialized function that only works for bouncing ball animation 2 and probably cannot be share-used by other function or script. Thus, it is preferred to put this callback function together with its main code instead of putting it in a separate m-file.
There are two elegant ways to solve the problems stated above. The first one is by encapsulating the script into a function m-file simply by addingfunction <function name> header andend footer. The other solution is to use OOP (Object-oriented programming) and create new class/object by usingclassdef header and end footer. Each solution has its own advantages and disadvantages. Creating the animation as a function instead of a class is simpler and can be done easily by adding two lines to the script and only requires some minor adjustments to the code. However, variable scope and management may get confusing and complicated as the function grows bigger and more variables are used. On the other hand, creating animation as a class allows custom client modifications and all other OOP features. However, it is quite complicated to implement and it is not feasible for simple animation.
The followingBouncingBallFunction m-file shows the function m-file created from Script01c. Notice that there is not much difference betweenBouncingBallFunction and Script01c. Function declaration (function header on line 1 and end footer on line 63) is added and theclosefigfcn function is included at the end of the code (line 56 to 60). In this m-file, all variables that are declared/assigned outside local function (line 13 to 21) are global variables. These variables exist throughout the entire function, even inside local closefigfcn function. Hence,play variable can be accessed and modified right away byclosefigfcn function (line 58), renderingassignin command unnecessary. Unfortunately, because of this feature, one should be careful not to mix and or re-use global variable as local variable in each local function or as an input argument declaration for a local function. This is why variable management can get quite confusing when creating animation in function form.
function BouncingBallFunction %-------------------------------------------------------------------------- %BouncingBallFunction %Creating Simple Animation in MATLAB %MATLAB Undercover %zerocrossraptor.wordpress.com %-------------------------------------------------------------------------- %This function m-file creates an endless animation of bouncing ball. %-------------------------------------------------------------------------- %CodeStart----------------------------------------------------------------- %Declaring ball's initial condition initpos=50; %Ball's initial vertical position initvel=0; %Ball's initial vertical velocity %Declaring environmental variable r_ball=5; %Ball's radius gravity=10; %Gravity's acceleration c_bounce=1; %Bouncing's coefficient of elasticity %Declaring animation timestep dt=0.0125; %Animation timestep %Initiating figure, axes, and objects for animation fig=figure('DeleteFcn',@closefigurefcn); axs=axes('Parent',fig); ball=rectangle('Position',[-r_ball,initpos,r_ball,r_ball],... 'Curvature',[1,1],... 'FaceColor','b',... 'Parent',axs); line([-5*r_ball,5*r_ball],... [0,0],... 'Parent',axs); %Executing animation pos=initpos-r_ball; %Ball's current vertical position vel=initvel; %Ball's current vertical velocity play=true; %Current animation status while play %Declaring time counter t_loopstart = tic(); %Updating ball's condition pos=pos+(vel*dt); %Ball's current vertical position vel=vel-(gravity*dt); %Ball's current vertical velocity if pos<0 vel=-vel*c_bounce; %Ball's current vertical velocity end %Updating ball set(ball,'Position',[-r_ball,pos,r_ball,r_ball]); %Preserving axes axis(axs,[-5*r_ball,5*r_ball,0,initpos+2*r_ball]); axis(axs,'equal'); axis(axs,'off'); %Pausing animation el_time=toc(t_loopstart); disp(['Elapse time : ',num2str(el_time),' seconds']); pause(dt-el_time); end %Declaring callback function function closefigurefcn(source,event) play=false; pause(1); end %CodeEnd------------------------------------------------------------------- end
The followingBouncingBallClass m-file shows the class m-file created from Script01c. The structure of this m-file is quite different compared with Script01c because it has to follow MATLAB's format for class definition. While the basic structure of OOP and class definition in MATLAB will not be explained here (For tutorial on creating new class in MATLAB, see my other tutorial, Creating Custom Class (OOP) in MATLAB *ToBeAdded*), it should be noted out that there is several way to run an animation with class m-file. The first one is by writing the entire code inside the class constructor (as shown in BouncingBallClass m-file below), thus allowing the animation to be played just by running the m-file. The other way is by writing the initialization inside the class constructor and putting the code for animation inside a public method. The advantage of putting the animation code inside public method is that the animation will not started until that method is called, thus, allowing object manipulation or perhaps customization of animation parameter before the animation is played. This way, the animation also can be re-run multiple times without re-doing the initialization. While this may seem trivial in a simple bouncing ball animation, but it will be useful when the animation is quite complicated and the initialization takes some time to be executed.
classdef BouncingBallClass<handle %-------------------------------------------------------------------------- %BouncingBallClass %Creating Simple Animation in MATLAB %MATLAB Undercover %zerocrossraptor.wordpress.com %-------------------------------------------------------------------------- %This class m-file creates an endless animation of bouncing ball in its %constructor method. %-------------------------------------------------------------------------- %CodeStart----------------------------------------------------------------- %Declaring class constants properties(Constant) %Declaring environmental variable r_ball=5; %Ball's radius gravity=10; %Gravity's acceleration c_bounce=1; %Bouncing's coefficient of elasticity %Declaring ball's initial condition initpos=50; %Ball's initial vertical position initvel=0; %Ball's initial vertical velocity %Declaring time step dt=0.0125; %Animation timestep end %Declaring class properties properties %Declaring variables for figure, axes, and plot objects fig; %Class' figure handle axs; %Class' axes handle ball; %Class' rectangle object for ball ground; %Class' line object for ground %Declaring variable for animation play; %Current animation status pos; %Ball's current vertical position vel; %Ball's current vertical velocity end %Declaring class method methods %Declaring constructor function this=BouncingBallClass() %Initiating GUI figure, axes, and objects for animation this.fig=figure('DeleteFcn',@(src,event)closefigurefcn(this)); this.axs=axes('Parent',this.fig); this.ball=rectangle('Position',[-BouncingBallClass.r_ball,... BouncingBallClass.initpos,... BouncingBallClass.r_ball,... BouncingBallClass.r_ball],... 'Curvature',[1,1],... 'FaceColor','b',... 'Parent',this.axs); this.ground=line([-5*BouncingBallClass.r_ball,... 5*BouncingBallClass.r_ball],... [0,0],... 'Parent',this.axs); %Executing animation this.pos=BouncingBallClass.initpos-BouncingBallClass.r_ball; this.vel=BouncingBallClass.initvel; this.play=true; while this.play %Declaring time counter t_loopstart=tic(); %Updating ball's condition this.pos=this.pos+(this.vel*BouncingBallClass.dt); this.vel=this.vel-(BouncingBallClass.gravity*... BouncingBallClass.dt); if this.pos<0 this.vel=-this.vel*BouncingBallClass.c_bounce; end %Updating ball set(this.ball,'Position',[-BouncingBallClass.r_ball,... this.pos,... BouncingBallClass.r_ball,... BouncingBallClass.r_ball]); %Preserving axes axis(this.axs,[-5*BouncingBallClass.r_ball,... 5*BouncingBallClass.r_ball,... 0,... BouncingBallClass.initpos+... 2*BouncingBallClass.r_ball]); axis(this.axs,'equal'); axis(this.axs,'off'); %Pausing animation el_time=toc(t_loopstart); disp(['Elapse time : ',num2str(el_time),' seconds']); pause(BouncingBallClass.dt-el_time); end end %Declaring callback function to end animation function closefigurefcn(this) this.play=false; pause(1); end end %CodeEnd------------------------------------------------------------------- end
It is up to individual preference to decide whether to create a function m-file or class m-file for the animation. Personally, I prefer to draft the code in script form for fast development (because I don't need to follow the class definition structure, which is quite complicated) and easy debugging (because I can see all the variable's values in the workspace) and then convert it into a function and put all the callback function in. The down side is that after the code is put together, it will be hard to debug the code and see all the variables.
5. Using 'xor' as EraseMode
Besides choosing a small enough time interval for animation update, another way that can be done to help create smooth animation is to modify plot object's EraseMode property. EraseMode controls how MATLAB erase and redraw the plot objects on the screen. By default, MATLAB sets EraseMode to 'normal', where a complete check is done to ensure the plot object is displayed correctly on the screen. Using 'normal' as EraseMode produce the most accurate visualization on the screen, but it is the slowest method. The other EraseMode that can be used are 'xor', 'background', and 'none' (for the explanation of each definition, see MATLAB's online documentation site). All of these will yield faster visualization, but will impair the visualization quality in some way. Among these three, 'xor' is the one mostly used when creating animation.
Using custom EraseMode for plot object is purely optional. However, keep in mind that using one will compromise the visualization quality. Basically, when a animation time interval is short enough, using custom EraseMode is not necessary as the animation is already smooth as it is. However, the smoothness of an animation is a subjective matter and each people may have different opinion on it. Thus, as a quick reference, the following videos were made to show the difference between 'normal' EraseMode and 'xor' EraseMode. These videos were made by running BouncingBallFunction with two different EraseMode (which is done by squeezing EraseMode property set up in between line 27 and 28). Note that the screen capture program itself put quite a strain on the CPU, thus causing both animations to be a little bit sluggish). Nevertheless, these videos still can clearly show the difference between 'normal' EraseMode result and 'xor' EraseMode result.
6. Summary
In short, to create an animation, one should create a plot and updates it periodically inside a while loop. Besides updating the plot, axis adjustment and pause command with appropriate time interval must be included also inside the while loop to create smooth animation. For better efficiency, figure object, axes object, and plot objects should be handled manually. Note animation can always be written in form of script, function, or class m-file. Before start writing, always think carefully which form that best suits your needs.
7. Resource (Example M-File)
Script01a.m – script m-file for sinusoidal animation
Script01b.m – script m-file for bouncing ball animation
Script01c.m – script m-file for bouncing ball animation with manual figure handling
closefigfcn.m – function m-file for callback function inScript01c
BouncingBallFunction.m – function m-file for bouncing ball animation
BouncingBallClass.m – class m-file for bouncing ball animation
FAQ
<to be added>
***
This tutorial is not perfect! If you still have any question or suggestion or correction regarding this tutorial, please feel free to leave a comment or email me atzerocross_raptor@yahoo.com.
***
Drawing Vertical Lines on a Plot Matlab
Source: https://zerocrossraptor.wordpress.com/matlab-undercover/creating-simple-animation-in-matlab/