MATLAB Animating Vector Addition in Matlab (Looking for improvements)

AI Thread Summary
The discussion centers around optimizing a MATLAB script for animating multiple vectors using the quiver function. The original code required repetitive copy-pasting for each new vector added, leading to inefficiency. The user sought advice on how to avoid this redundancy while maintaining functionality. Key improvements included restructuring the plotting logic to retain variables outside of conditional statements, allowing for a more streamlined approach. By plotting vectors in a single loop and updating their properties based on iteration counts, the user was able to eliminate the need for multiple if-else statements. This adjustment not only simplified the code but also enhanced its scalability for adding more vectors without excessive duplication. The final solution effectively produced the desired animation while adhering to best coding practices.
PhDeezNutz
Messages
849
Reaction score
556
TL;DR Summary
I eventually want to create a vector addition graphic in matlab. As in the literal "head to tail" idea.
Here is my code thus far and it seems to work (I've attached a gif as well so hopefully that works)
Matlab:
va1 = [50*cos(pi/3), 50*sin(pi/3)]; %Two different vectors both starting from the origin
vb1 = [20*cos(pi/6), 20*sin(pi/6)];

iterator = linspace(1,100,100); %100 iterations for the animation inside the for loop
vaiteratorx = linspace(0,50*cos(pi/3),100); % The ending x points for the first vector in successive animations
vaiteratory = linspace(0,50*sin(pi/3),100); % The ending y points for the first vector in successive animations

vbiteratorx = linspace(0,20*cos(pi/6),100); % The ending x points for the second vector in successive animations
vbiteratory = linspace(0,20*sin(pi/6),100);    % The ending y points for the second vector

for i = 1:length(iterator)
    clf
    
    if i <=50
        
        
        initial_point1 = [0,0];
        dp = [2*vaiteratorx(i) 2*vaiteratory(i)];
        q1 = quiver(0,0,2*vaiteratorx(i),2*vaiteratory(i),0,'color','m','linewidth',3,'MaxHeadSize',0.25);
        hold on
 
    else
      
        q1 = quiver(0,0,vaiteratorx(end),vaiteratory(end),0,'color','m','linewidth',3,'MaxHeadSize',0.25);
        hold on
        initial_point2 = [0,0];
        dp2 = [2*vbiteratorx(i-50) 2*vbiteratory(i-50)];
        q2 = quiver(0,0,dp2(1),dp2(2),0,'color','c','linewidth',3,'MaxHeadSize',50*0.25/20);
        hold on
          
            end
    
  
    xlim([0 200])
    ylim([0 ceil(9*200/16)]);
    set(gca,'color','k');
    set(gcf,'color','k');
    Ax = gca;
    Ax.XAxis.Visible = 'off';
    Ax.YAxis.Visible = 'off';
    Ax.XGrid = 'off';
    Ax.YGrid = 'off';
    Ax.Color = 'none';
    fig=gcf;
    fig.Units='normalized';
    fig.OuterPosition=[0 0 1 1];

    movieVector(i) = getframe(gcf)
end

myWriter = VideoWriter('SlideTwo','MPEG-4');
myWriter.FrameRate = 1;

open(myWriter)
writeVideo(myWriter,movieVector)
close(myWriter)

What I want to avoid doing is copying and pasting the last part of the last if block for each new else or elseif statement.

If I want to add to eventually add say 30 things to the animation then I will have to copy the last parts 30 times.How do I get around this?

Notice i had to replot "quiver1" for the "else" statement. I would hate to do this endlessly for successive parts.

Anyway I would appreciate any advice about how to approach this and here's the gif.
SlideTwo.gif


Wow that gif is slow.
 
Physics news on Phys.org
I presume you mean something like this?

[CODE lang="matlab" title="Plot vectors"]% Start with a clean slate
close all; clear all; clc;

% How many frames should be used to grow one vector
nFramesPerVector = 50;

% Just an example from quiver help to generate some vectors
% X = all x-coordinates of all vectors, likewise Y. U is
% length in X direction, likewise V.
[X,Y] = meshgrid(1:6,1:6);
U = 0.25*X;
V = 0.5*Y;

% Total amount of vectors
nvectors = numel(X);

% You need to generate the figure only once
fig = figure('Position', [0 0 1 1]);
fig.Units='normalized';
xlim([0 8])
ylim([0 9])
set(gca,'color','k');
set(gcf,'color','k');
Ax = gca;
Ax.XAxis.Visible = 'off';
Ax.YAxis.Visible = 'off';
Ax.XGrid = 'off';
Ax.YGrid = 'off';
Ax.Color = 'none';
hold on;

% A counter for the total amount of frames
iframe = 1;

% Loop over the vectors
for ivec = 1:nvectors

% Loop over the frames to grow one vector
for i = 1:nFramesPerVector

% Scale factor for the vectors
scaleFactor = i/nFramesPerVector;

% Plot the vector
q1 = quiver(X(ivec),Y(ivec), ...
scaleFactor*U(ivec),scaleFactor*V(ivec),0,'color','m',...
'linewidth',2,'MaxHeadSize',0.25);

% Save frame
movieVector(iframe) = getframe(gcf);

% Delete vector unless it is the final, full-sized vector
if i ~= nFramesPerVector
delete(q1)
end

% Increase frame counter
iframe = iframe + 1;
end
end

myWriter = VideoWriter('SlideTwo');
myWriter.FrameRate = 24;

open(myWriter)
writeVideo(myWriter,movieVector)
close(myWriter)[/CODE]
 
I will try it as soon as I get home from thanksgiving dinner! Thank you very much for your response!
 
It was a simple fix. The overall structure was a bunch of if, elseif, else statements nested in a for loop. The problem was that I wasn't retaining the plots to update as the script goes to the next if statement. This was because the plotting was inside the if statements and therefore limited to that scope.

The fix was updating the variables inside the if block and plotting it outside of the if block (before the end of the for loop) while invoking the command "hold on".

The script is as follows and it produces exactly what I want. @Arjan82 's ideas helped me realize that I needed to think about scope.

[CODE lang="matlab" title="Fixed Vector Addition Animation"]va1 = [50*cos(pi/3), 50*sin(pi/3)]; %Two different vectors both starting from the origin
vb1 = [20*cos(pi/6), 20*sin(pi/6)];

iterator = linspace(1,150,150); %100 iterations for the animation inside the for loop
vaiteratorx = linspace(0,50*cos(pi/3),150); % The ending x points for the first vector in successive animations
vaiteratory = linspace(0,50*sin(pi/3),150); % The ending y points for the first vector in successive animations

vbiteratorx = linspace(0,20*cos(pi/6),150); % The ending x points for the second vector in successive animations
vbiteratory = linspace(0,20*sin(pi/6),150); % The ending y points for the second vector

% vabiteratorx = linspace(0,-(20*cos(pi/6) - 50*cos(pi/3)),150);
% vabiteratory = linspace(0,-(20*sin(pi/6) - 50*cos(pi/3)),150);

dp = [0,0];
dp2 = [0,0];
dp3 = [0,0];

for i = 1:length(iterator)
clf



if i <=50
dp = [3*vaiteratorx(i), 3*vaiteratory(i)];
elseif i <= 100
dp2 = [3*vbiteratorx(i-50) 3*vbiteratory(i-50)];
else
dp3 = [3*(vaiteratorx(i-100) - vbiteratorx(i-100)), 3*(vaiteratory(i-100) - vbiteratory(i-100))];
end

q1 = quiver(0,0,dp(1),dp(2),0,'color','m','linewidth',3,'MaxHeadSize',0.25);
hold on

q2 = quiver(0,0,dp2(1),dp2(2),0,'color','c','linewidth',3,'MaxHeadSize',50*0.25/20);
hold on

q3 = quiver(20*cos(pi/6),20*sin(pi/6),dp3(1),dp3(2),0,'color','c','linewidth',3,'MaxHeadSize',0.25);
hold on

xlim([0 200])
ylim([0 ceil(9*200/16)]);
set(gca,'color','k');
set(gcf,'color','k');
Ax = gca;
Ax.XAxis.Visible = 'off';
Ax.YAxis.Visible = 'off';
Ax.XGrid = 'off';
Ax.YGrid = 'off';
Ax.Color = 'none';
fig=gcf;
fig.Units='normalized';
fig.OuterPosition=[0 0 1 1];

movieVector(i) = getframe(gcf)
end

myWriter = VideoWriter('SlideTwoTwo','MPEG-4');
myWriter.FrameRate = 1;

open(myWriter)
writeVideo(myWriter,movieVector)
close(myWriter)[/CODE]
 
Well, you've asked how to do this when you have 30 vectors without all of the copy-pasting. Your solution still does a lot of unnecessary copy pasting and has lots of double code (try doing this for 30 vectors).

But if it works for you it's fine I guess :).
 

Similar threads

Replies
1
Views
4K
Replies
3
Views
4K
Back
Top