Search code examples
matlabmatlab-figurepde

How do i produce an animated GIF in MATLAB?


I want to produce a animated gif of a solution to a partial differential equation. That is the gif should show the solution at specific time.

example

Currently I can only make pictures in which all times are plotted. Below is my entire program, with figure(3) being my attempt of making a gif.

clear all;
close all;
%%%%%%%%%%%%
% For slide 27 of Diffusion 1D
% The equation to be graphed in latex form is
% u(x,t)=\frac{1}{L}+\frac{2}{L}\sum^{\infty}_{n=1}cos(\frac{n\pi x_0}{L})cos(\frac{n\pi x}{L})e^{-k(\frac{n\pi}{L})^2t}
%%%%%%%%%%%%

%define constants
%note that the constants listed in the file are arbitrary
L = 2; %length of the rod
k= 0.01; % Diffusivity, which is assume to be constant but can be a function of x
x0 = 1; %location of the inital condition i.e. f(x)=delta(x-x0)
tmax= 50; %maximum amount of time the simulation runs
nmax = 200; % maximum value for n, increase to accuracy
tgrid = 21; %The number of points to be evaluated in the time domain
xgrid = 51; %The number of points to be evaluated in the space domain

%initialize variables
u=zeros(tgrid,xgrid); %preallocate array used for storing values of the solution
t=linspace(0,tmax,tgrid);%We assume that time is evenly distributed
x=linspace(0,L,xgrid); %We assume that space is evenly distributed

%Plotting variables
figure(1);
hold on;
axis([0 L -inf inf]);
xlabel('x');
ylabel('u(x,t)');
%Calculation,
for i=1:tgrid
    for j=1:xgrid
        seriesSum=0;
        %Calculate the fourier series up to nmax for each point u(x,t)
        for n= 1:nmax
            seriesSum= seriesSum + cos(n*pi*x0/L)*cos(n*pi*x(j)/L)*exp(-k*t(i)*(n*pi/L)^2);
        end
        %Finish calcuation for solution at a specific point
        u(i,j)= 1/L+(2/L)*seriesSum;
    end
    %After we have calculated all points at time t, we graph it for time t
    plot(x,u(i,:),'linewidth',4);
end
saveas(gcf,'PDE_sol.png')%Save figure as png in current directory

%run a second loop that does not include the initial condition to get a
%better view of the long term behaviour.
%Plotting variables
figure(2);
hold on;
axis([0 L -inf inf]);
xlabel('x');
ylabel('u(x,t)');
for i=2:tgrid
    plot(x,u(i,:),'linewidth',4);
end
saveas(gcf,'PDE_sol_without_inital.png')%Save figure as png in current directory

%Create a gif verison of figure 2
figure(3);
axis([0 L -inf inf]);
xlabel('x');
ylabel('u(x,t)');
filename = 'PDE_sol.gif';
for i=2:tgrid
    plot(x,u(i,:),'linewidth',4);
    drawnow
    frame = getframe(1);
    im = frame2im(frame);
    [imind,cm] = rgb2ind(im,256);

    if i == 2;
        imwrite(imind,cm,filename,'gif', 'Loopcount',inf);
    else
        imwrite(imind,cm,filename,'gif','WriteMode','append');
    end
end

The output gif that I get is

this

which is clearly not animated.

Note: If you think there is a better place to post this question please direct me to it. As my issue is with the MATLAB programming language and not the math involved I thought this would be the best place to post my question.


Solution

  • The first input to getframe is the handle of the figure that you'd like to take a screenshot of. As you have it written, you are grabbing figure 1 which is actually referring to the first figure that you create that you aren't updating within your loop.

    You have assigned a numeric handle of 3 to the figure that you create right before your last loop so you'll want to tell getframe to use that figure instead.

    Additionally, I would create one plot object and update the XData and YData rather than continuously creating new plot objects. The issue with calling plot continuously is that it's slow AND it completely resets all of your axes settings such as x and y labels as well as x and y limits.

    % Store the handle to the figure in hfig
    hfig = figure(3);
    
    % Create the initial plot object
    hplot = plot(NaN, NaN, 'LineWidth', 4);
    
    axis([0 L 0 2]);
    xlabel('x');
    ylabel('u(x,t)');
    
    filename = 'PDE_sol.gif';
    
    for i=2:tgrid
        % Update the plot appearance
        set(hplot, 'XData', x, 'YData', u(i,:));
        drawnow
    
        % Get a screenshot of THIS figure
        frame = getframe(hfig);
        im = frame2im(frame);
    
        [imind,cm] = rgb2ind(im,256);
    
        if i == 2;
            imwrite(imind,cm,filename,'gif', 'Loopcount',inf);
        else
            imwrite(imind,cm,filename,'gif','WriteMode','append');
        end
    end
    

    enter image description here