How do you plot a graph evolving over time? - matlab

I have data about a network showing edges and nodes such as:
edges = ...
[5 7 1;
5 7 2;
5 11 2;
5 7 3;
5 11 3;
5 16 3;
5 7 4;
5 11 4;
5 16 4;
5 21 4];
I'd like to obtain multiple different plots based on how those edges evolve because those edges are the result of a long observation (e.g. one year).
Each edge occurs at a different moment and therefore, I'd like to get those six different plots separately.
Suppose, the first month I see these edges:
edges = ...
[5 7 1];
And in the second month, I see this:
edges = ...
[5 7 2;
5 11 2;];
And month by month, more edges are added until the complete data set show above is obtained.
EDIT
The third column is the moment identifier and using this article (Filter Matrix by some column value
) I can loop through the matrix and obtain a filtered_edges to use in the graph() function.
END EDIT
The easy way would be to create different edges files and read them one by one, but is there a way to do this programmatically with Matlab?

See the mathworks documentation for details. For your case, here you go:
data = rand(6,2);
figure
% You need to somehow fix your axes, so that they don't resize
axis tight manual
ax = gca;
ax.NextPlot = 'replaceChildren';
% Let's record this to file
v = VideoWriter('myAnimation.avi');
v.FrameRate = 10; % slow down the animation
open(v);
loops = size(data,1);
F(loops) = struct('cdata',[],'colormap',[]); % Struct to hold frames
for i = 1:loops
plot(data(1:i,1),data(1:i,2),'*'); % plot what you want in the new frame
drawnow % clear and draw new frame
frame = getframe;
F(i) = frame; % if you want to animate locally you only need this
pause(0.1); % this just slows down locally, can be removed and does NOT influence the saved video
writeVideo(v,frame); % this is only if you want to save to file
end
close(v);

Related

A question about drawing a surface plot in MATLAB

I wrote a matlab code for topology optimization. The code showing the results in a surface plot is:(a very simple example)
XYZG=[2.5 0 0;2.5 0 2.5;2.5 0 5;0 -2.5 0;0 -2.5 2.5;0 -2.5 5;-2.5 0 0;-2.5 0 2.5;-2.5 0 5];
ELNOD=[1 4 5 2;2 5 6 3;4 7 8 5;5 8 9 6];
nelement=4;
Dens=[0 1 1 0];
for element=1:nelement
for i=1:4
X(i)=XYZG(ELNOD(element,i),1);
Y(i)=XYZG(ELNOD(element,i),2);
Z(i)=XYZG(ELNOD(element,i),3);
end
XX=[X(1) X(2);X(4) X(3)];
YY=[Y(1) Y(2);Y(4) Y(3)];
ZZ=[Z(1) Z(2);Z(4) Z(3)];
tick=-Dens(element)*[1 1;1 1];
figure(1)
hold on
surf(XX,YY,ZZ,tick);
colormap gray;
end
This code is too slow. If I have for example 10,000 elements it takes a long time for drawing plot.
So I would appreciate any help on how to make this faster.
1] Minor improvement:
The code you gave as a sample can be simplified to avoid temporary assignment. Consider the following:
%% Sample data
XYZG=[2.5 0 0;2.5 0 2.5;2.5 0 5;0 -2.5 0;0 -2.5 2.5;0 -2.5 5;-2.5 0 0;-2.5 0 2.5;-2.5 0 5];
ELNOD=[1 4 5 2;2 5 6 3;4 7 8 5;5 8 9 6];
nelement=4;
Dens=[0 1 1 0];
%% pre-initialisation just to set the size (size=[2,2])
XX = zeros(2) ;
YY = XX ;
ZZ = XX ;
figure(1)
hold on
colormap gray;
for element=1:nelement
% Base vector combining (unused now)
% idx=1:4;
% X = XYZG( ELNOD(element,idx),1 ).';
% Y = XYZG( ELNOD(element,idx),2 ).';
% Z = XYZG( ELNOD(element,idx),3 ).';
% The block above is commented because we do not need these intermediate
% vectors to build the base matrices XX, YY and ZZ.
% This can be done directly using linear indexing:
idxOrder = [1 4 2 3] ;
XX(1:4) = XYZG( ELNOD(element,idxOrder) , 1 ) ;
YY(1:4) = XYZG( ELNOD(element,idxOrder) , 2 ) ;
ZZ(1:4) = XYZG( ELNOD(element,idxOrder) , 3 ) ;
tick=-Dens(element)*[1 1;1 1];
surf(XX,YY,ZZ,tick) ;
end
This should run marginally faster. Thanks to the avoidance of a few temporary arrays. We are now building each patch coordinates more directly. Also the function calls which only need to be used once have been taken out of the loop (something to generally look for if your loop is taking too long).
Now this is not going to be satisfying anyway. The real bottleneck in your structure is not so much the calculations/indexing in each loop iteration, it is the growing number of graphic handles that the system has to maintain. Every iteration of your loop create a surface object. These objects require memory to keep their coordinates, but also to maintain the large number of internal properties. Once you multiply these objects, your system will start to slow down. Some systems may not even be able to create 10,000 surface graphic objects on the same figure, and if they can it's going to be sluggishly painful (you know these situations where you click on the screen and wait ~25s to notice any reaction ...).
2] Major improvement:
One way to limit the number of graphic object would be to combine all of these cordinates in order to create a single graphic object. Of course we'd then have to color each face according to your rule.
Fortunately, I noticed that your base coordinates are actually organised perfectly to inject directly as a patch in Matlab. SO no need to demultiplex/remultiplex the data in and out, we can directly create and color a global patch:
% create a Black and White colormap
cmap = [1 1 1;
0 0 0] ;
figure
% generate a patch with all the 'faces','vertices' and 'color' data :-)
hp = patch('Faces',ELNOD, 'Vertices',XYZG, 'FaceVertexCData',Dens(:) ) ;
% last refinement to have the same appearance than in former code
shading flat
colormap(cmap)
hp.EdgeColor = 'k' ; % <= this needs to be executed AFTER "shading flat"
Voila !! No need any loop or any calculations. You already had all the data needed in the first place ;-)
I'd encourage you to read the documentation for patch, especially the way to use the property FaceVertexCData

Exchange subplots in figure

I create a figure containing 4 subplots like:
y = [2 2 3; 2 5 6; 2 8 9; 2 11 12];
fig = figure
for i = 1 : 4
h(i) = subplot(1,4,i)
bar(y)
end
Now I would like to exchange the order of the subplots. For example the first subplot should go in the last column (4th) and the 2nd subplot should exchange with the 3rd.
Is it doable without generating again the figure?
Perhaps you could change their 'position' of the axes h. For instance:
% get position
pos = get(h,'position');
% change position, 1st <-> 4th, 2nd <->3rd.
set(h(1),'position',pos{4});
set(h(4),'position',pos{1});
set(h(2),'position',pos{3});
set(h(3),'position',pos{2});
There is a possibility which kind of regenerates the figure. You can go to the plot tools, right click the figure and select "Show code". This will open a new file with a function that recreates the figure. There you can change your subplot-position and call the function in order to obtain the figure with switched subplots.
While this recreates the figure, you do not have to re-evaluate the function or script that originally created the figure.
PS: I'm not sure how new this feature is.
In addition to swapping the Position property of the axes objects, you could also swap the Parent property of the bar objects. This has the advantage of leaving your axes positioning intact.
A simple example:
function testcode
y1 = [2 2 3; 2 5 6; 2 8 9; 2 11 12];
y2 = -y1;
h(1) = subplot(1, 2, 1);
b(1,:) = bar(y1);
h(2) = subplot(1, 2, 2);
b(2,:) = bar(y2);
swapbar(h, b, [1,2]);
end
function swapbar(axesobjects, barobjects, axesswap)
set(barobjects(axesswap(1), :), 'Parent', axesobjects(axesswap(2)));
set(barobjects(axesswap(2), :), 'Parent', axesobjects(axesswap(1)));
end
Here I've created a small helper function swapbar to swap two axes. This isn't at all a robust implementation but it works well to illustrate the concept.
Old:
New:

Sliding window for matlab

The intention is to estimate in a [3 3] sliding window. 0.5*[(A(i)-A(5))^2] is computed where a(i) is the pixels around center pixel a(5).
The mean of each of these 8 half square differences is stored in the center pixel's location.
To tackle this conv2 and nlfilter were used on a training example matrix as follows.
clc;
close all;
clear all;
A = [1 2 3 4 5 6;5 4 6 3 2 1;2 3 2 1 4 5];
kernel = [-1 -1 -1; -1 8 -1; -1 -1 -1];
outputImage = conv2(A, kernel);
fun = #(x) mean(x(:));
B= nlfilter (outputImage,[3 3],fun);
The initial idea was to calculate the difference and store it in the location of the pixels instead of the center pixel. Then use a sliding window to take mean of those differences and replace the center pixel.
It was apparent that my logic was flawed.
Though i was able to calculate the difference(i first tried to see simple difference was possible for me) i had to deal with data being overwritten. moreover this method will create a matrix larger than the original which is also wrong.
the function mean and the kernel you are using are both linear and do not represent the non-linear operation you are trying to achieve.
One way of using conv and mean is by computing the 8 differences as different output channels
ker = cell(1,8);
for ii=1:8
ker{ii} = zeros(3);
ker{ii}(2,2) = 1; %// for a(5)
if ii < 5
ker{ii}(ii) = -1;
else
ker{ii}(ii+1) = -1;
end
end
interim = zeros( [size(A,1) size(A,2), numel(ker)] ); % allocate room for intermidiate results
for ii=1:numel(ker)
interim(:,:,ii) = conv2(A, ker{ii}, 'same' ); %//'same' takes care of output size for you
end
Now interim holds each of the different a(5)-a(i) we are ready for the non-linear operation
interim = interim.^2;
B = 0.5 * interim;

How do I add values to a vector when I do not have a subindex specified

I am working on a Bézier curve and this how my code looks right now
x=[3 2 6 4 1];
y=[8 1 7 5 9];
n=length(x)-1;
scatter(x,y)
hold on
for t=0:0.01:1
for i=0:1:n
xt=nchoosek(n,i)*(t^i)*(1-t)^(n-1)*x(n+1);
yt=nchoosek(n,i)*(t^i)*(1-t)^(n-1)*y(n+1);
end
end
plot(xt,yt)
hold off
I'm a beginner using Matlab so I'm experiencing some issues. I would like to know how to make xt and yt vectors of the same size as t (that means 101x1) and make the values they get while just i changes be added to the other values as long as t is the same. When t changes, they must start from 0 and add the values they get while just i changes until it gets to n.
Thank you
The variable xt and yt should be vectors and their tth value updated at each iteration of i. Try:
x=[3 2 6 4 1];
y=[8 1 7 5 9];
n=length(x)-1;
scatter(x,y)
hold on
T = 0:0.01:1
xt = zeros(size(T));
yt = zeros(size(T));
for idt = 1:length(T)
t=T(idt);
for i=0:1:n
xt(idt)=xt(idt)+nchoosek(n,i)*(t^i)*(1-t)^(n-i)*x(i);
yt(idt)=yt(idt)+nchoosek(n,i)*(t^i)*(1-t)^(n-i)*y(i);
end
end
plot(xt,yt)
hold off

Adding a curve to Matlab Figure

I have written a program that takes a lot of data and produces graphs.It would be really convenient and save me a lot of time if I could take curves on an existing figure and add their values together to make a single curve. For a simple example lets say I have the following code,
x = [0 1 2 3 4 5];
y = [0 1 2 3 4 5];
z = [4 6 2 8 7 9];
figure
plot(x,y,x,z)
This code will produce a figure with two curves. Without modifying the code or re-running the program, and only working with the figure options I would like to add the curve y + z to the plot. Is this possible? Thanks.
The reason I don't want to add the functionality is the plot code is buried within 8 loops
that calls data from a 4D cell array of file name strings.
If you have the x, y and z variable used in the plot you can just add new lines to the plot with
hold on
plot(x,y+z)
hold off
If you don't have them directly (they were generated in a function, for example, you can always get them from figure with XData, YData properties of line objects.
hline = findobj(gca,'type','line');
x = get(hline,'XData');
y = get(hline,'YData');
X = x{1}; % let's assume that all lines have the same x values.
Y = sum(cell2mat(y));
hold on
plot(X,Y)
hold off