Search code examples
matlabanimationplotmatlab-figure

MatLab: updating two separate, animated figures, visualizing weight and error


I am trying to visualize a small simulation I have to do. For the task, it is not necessary but as it quite often happens: I run into the problem and want the solution before I go on.

The simulation is an ultra-simple neural net from the computational neuroscience department with an 'Oja' algorithm. I have the value plotted as scatterplot and wanted to animate the changing weight over the loops. That for itself works fine (figure 2 or f2 handle) Then I decided to print the difference in the weight vector from one run to another calculated as the norm. I wanted this to be plotted as a line that evolves over time (figure 1 aka f1). But though I always activate figure 2 it switches back to figure 1 and plots it there.

Of course, I searched the internet as well as stackexchange where btw I found lots of fascinating stuff about animations. Just nothing that solved the problem...

Two questions:

  1. why?
  2. and what do I have to change to make it work?

Thanks.

Here is the code:

function [t, w, dw]=weight(X)

w=rand(2,1)*5; %Initialization

%constants
n=1; 
alpha=1;
dt=0.01;
T=5;
L=length(X);
w_old=[0; 0];
s=size(w_old)
t=0;
limit=0.001;


%handles for the figures Error and weight animation
f1= figure
set(f1,'DoubleBuffer','on', 'Name','Error');
ax1 = axes('Position',[0.1 0.1 0.7 0.7]);

f2=figure
set(f2, 'Name', 'weights');

%normalizing and plot
X=[X(:,1)-mean(X(:,1)),X(:,2)-mean(X(:,2))];
scatter(X(:,1),X(:,2));

%function handle for the error and the weights animation
herror = animatedline('Marker','.');

hLine = line('XData',w(1), 'YData',w(2), 'Color','r', ...
    'Marker','o', 'MarkerSize',6, 'LineWidth',2);
hTxt = text(w(1), w(2), sprintf('(%.3f,%.3f)',w(1),w(2)), ...
    'Color',[0.2 0.2 0.2], 'FontSize',8, ...
    'HorizontalAlignment','left', 'VerticalAlignment','top');

while (t<T)
    for i=1:L
        w_old= w;
        u=X(i,:);
        v=u*w;
        w=w+dt*n*(v*u'-alpha*v^2*w);   %Oja rule
        figure(f2);
        hold on;
        set(hLine, 'XData',w(1), 'YData',w(2))   
        set(hTxt, 'Position',[w(1) w(2)], ...
        'String',sprintf('(%.3f,%.3f,%.2f)',[w(1) w(2) t]))        
        drawnow %# force refresh
        %#pause(DELAY)  
        hold off;
        dw=norm(w_old-w);
        figure(f1)
        hold on;
        addpoints(herror, (i*t/dt),dw)
        drawnow
        hold off;
        if dw<limit,  break; end
    end
    t=t+dt;

    if ~ishandle(hLine), break; end  
end
end

Solution

  • You created a new axes ax1 overlapping to the plot hiding the animation. You also put herror = animatedline('Marker','.'); after f2=figure doing nothing in the first figure before the for loop. This is the working code:

    function [t, w, dw]=weight(X)
    X = randn(20,2);
    w=rand(2,1)*5; %Initialization
    
    close all
    
    %constants
    n=1;
    alpha=1;
    dt=0.01;
    T=5;
    L=length(X);
    w_old=[0; 0];
    s=size(w_old);
    t=0;
    limit=0.001;
    
    
    %handles for the figures Error and weight animation
    f1= figure(1);
    hold on;
    set(f1,'DoubleBuffer','on', 'Name','Error');
    %ax1 = axes('Position',[0.1 0.1 0.7 0.7]);
    %function handle for the error and the weights animation
    herror = animatedline('Marker','.');
    xlabel('t'); ylabel('Error');
    
    f2=figure(2);
    hold on;
    set(f2, 'Name', 'weights');
    xlabel('W1'); ylabel('W2')
    
    %normalizing and plot
    X=[X(:,1)-mean(X(:,1)),X(:,2)-mean(X(:,2))];
    scatter(X(:,1),X(:,2));
    
    hLine = line('XData',w(1), 'YData',w(2), 'Color','r', ...
        'Marker','o', 'MarkerSize',6, 'LineWidth',2);
    hTxt = text(w(1), w(2), sprintf('(%.3f,%.3f)',w(1),w(2)), ...
        'Color',[0.2 0.2 0.2], 'FontSize',8, ...
        'HorizontalAlignment','left', 'VerticalAlignment','top');
    
    while (t<T)
        for i=1:L
            w_old= w;
            u=X(i,:);
            v=u*w;
            w=w+dt*n*(v*u'-alpha*v^2*w);   %Oja rule
    
            set(hLine, 'XData',w(1), 'YData',w(2))
            set(hTxt, 'Position',[w(1) w(2)], ...
                'String',sprintf('(%.3f,%.3f,%.2f)',[w(1) w(2) t]))
            drawnow %# force refresh
    
            dw=norm(w_old-w);
            figure(f1);
            addpoints(herror, (i*t/dt),dw)
            drawnow
            if dw<limit; break; end
    
        end
        t=t+dt;
    
        if ~ishandle(hLine), break; end
    end
    end
    

    To me, it seems more natural using just one window and 2 subplots instead of switching window back and forth.