How to determine the dimensions of a subplot in Matlab? - matlab

So I am writing a function that plots matrix data from n different cells. If n is 10, it should display 10 equally spaced plots on a single figure. If n is 7, it should try to space them out as equally as possible (so 3x2 or 2x3 plots with a plot by itself).
I am able to get these graphs drawn using subplot() and plot() but I'm having a hard time finding out how to initialise the dimensions for the subplot.
The number of subplots will be changing after each run so I can't initialise it to specific dimensions.
Can anyone point me in the right direction?

I am afraid problems like this tend to be messy. This normally problems like this need to be solved for different cases.
if (mod(n,2) && n<8)
% Do something
elseif (!mod(n,2) && n < 11)
% Do something else
elseif ...
....
end
The conditions are choosen a bit arbitarily since the specifications in the OP seemed a bit arbitary too. You probably understand the point and can set your own conditions.
There are two reasons why I recommend this approach.
1) This makes the code simpler to write. You do not have to come up with some complicated solution which may break in after some time.
2) By adding cases you can protect yourself against a rampant number of plots. In case the number of plots gets too large you do typically not want to have all plots in the same figure. It is also possible to wrap this into a function and apply this to X plots at a time in a loop. Typically you would want each iteration to be a separate figure.
It is not very easy to elaborate more on this since you have not yet specified how many cases you expect or what will happen to the last plot in case of odd numbers. Still this may give a good hint.
Good luck!

Another simple solution would be using round and ceil on the square root:
for n=1:20
[n, round(sqrt(n))*ceil(sqrt(n)), round(sqrt(n)), ceil(sqrt(n))]
end
output:
%(n, total_plots, x, y)
1 1 1 1
2 2 1 2
3 4 2 2
4 4 2 2
5 6 2 3
6 6 2 3
7 9 3 3
8 9 3 3
9 9 3 3
10 12 3 4
Usage example:
n = 7
subplot(round(sqrt(n)), ceil(sqrt(n)), plot_nr_x) % switch first 2 params to have either a slightly longer or slightly wider subplot

I ran into a very similar problem today and I was having a lot of trouble to define the size of the subplot that would fit everything. My reasoning is mostly a hack but it can help. If you have to represent at most n figures, you can thing as a square grid of sqrt(n) * sqrt(n). To make things better we add a safety row, so the final matrix would be (sqrt(n) + 1) * sqrt(n). I hope this helps solving your problem.
In my code have 2 nested loops:
within a loop that opens a figure for each kk element and is meant to plot a particular graph from the x position within the array.
for kk=1:length(some_file_list)
% Load data
% do some math
% get data as a cell array with things we care about in data(3,)
array_size = size(data(3,:),2);
for x=1:size(data(3,:),2);
% do more math and get things ready to plot matrix_A scaled by range_A
figure(kk); % open figure
grid_rows = round((sqrt(array_size)+1));
grid_cols = round(sqrt(array_size));
% plot
subplot(grid_rows, grid_cols, x);
imagesc(matrix_A,range_A); %plot in position
colormap(gray);
end
end

Related

Average on contiguos segments of a vector

I'm sure this is a trivial question for a signals person. I need to find the function in Matlab that outputs averaging of contiguous segments of windowsize= l of a vector, e.g.
origSignal: [1 2 3 4 5 6 7 8 9];
windowSize = 3;
output = [2 5 8]; % i.e. [(1+2+3)/3 (4+5+6)/3 (7+8+9)/3]
EDIT: Neither one of the options presented in How can I (efficiently) compute a moving average of a vector? seems to work because I need that the window of size 3 slides, and doesnt include any of the previous elements... Maybe I'm missing it. Take a look at my example...
Thanks!
If the size of the original data is always a multiple of widowsize:
mean(reshape(origSignal,windowSize,[]));
Else, in one line:
mean(reshape(origSignal(1:end-mod(length(origSignal),windowSize)),windowSize,[]))
This is the same as before, but the signal is only taken to the end minus the extra values less than windowsize.

Trying to produce exponential traffic

I'm trying to simulate an optical network algorithm in MATLAB for a homework project. Most of it is already done, but I have an issue with the diagrams I'm getting.
In the simulation I'm generating exponential traffic, however, for low lambda values (0.1) I'm getting very high packet drop rates (99%). I wrote a sample here which is very close to the testbench I'm running on my simulator.
% Run the simulation 10 times, with different lambda values
l = [1 2 3 4 5 6 7 8 9 10];
for i=l(1):l(end)
X = rand();
% In the 'real' simulation the following line defines the time
% when the next packet generation event will occur. Suppose that
% i is the current time
t_poiss = i + ceil((-log(X)/(i/10)));
distr(i)=t_poiss;
end
figure, plot(distr)
axis square
grid on;
title('Exponential test:')
The resulting image is
The diagram I'm getting in this sample is IDENTICAL to the diagram I'm getting for the drop rate/λ. So I would like to ask if I'm doing something wrong or if I miss something? Is this the right thing to expect?
So the problem is coming from might be a numerical problem. Since you are generating a random number for X, the number might be incredibly small - say, close to zero. If you have a number close to zero numerically, log(X) is going to be HUGE. So your calculation of t_poiss will be huge. I would suggest doing something like X = rand() + 1 to make sure that X is never close to zero.

Graphing different sets of data on same graph within a ‘for’ loop MATLAB

I just have a problem with graphing different plots on the same graph within a ‘for’ loop. I hope someone can be point me in the right direction.
I have a 2-D array, with discrete chunks of data in and amongst zeros. My data is the following:
A=
0 0
0 0
0 0
3 9
4 10
5 11
6 12
0 0
0 0
0 0
0 0
7 9.7
8 9.8
9 9.9
0 0
0 0
A chunk of data is defined as contiguous set of data, without interruptions of a [0 0] row. So in this example, the 1st chunk of data would be
3 9
4 10
5 11
6 12
And 2nd chunk is
7 9.7
8 9.8
9 9.9
The first column is x and second column is y. I would like to plot y as a function of x (x is horizontal axis, y is vertical axis) I want to plot these data sets on the same graph as a scatter graph, and put a line of best fit through the points, whenever I come across a chunk of data. In this case, I will have 2 sets of points and 2 lines of best fit (because I have 2 chunks of data). I would also like to calculate the R-squared value
The code that I have so far is shown below:
fh1 = figure;
hold all;
ah1 = gca;
% plot graphs:
for d = 1:max_number_zeros+num_rows
if sequence_holder(d,1)==0
continue;
end
c = d;
while sequence_holder(c,1)~=0
plot(ah1,sequence_holder(c,1),sequence_holder(c,num_cols),'*');
%lsline;
c =c+1;
continue;
end
end
Sequence holder is the array with the data in it. I can only plot the first set of data, with no line of best fit. I tried lsline, but that didn't work.
Can anyone tell me how to
-plot both sets of graphs
-how to draw a line of best fit a get the regression coefficient?
The first part could be done in a number of ways. I would test the second column for zeroness
zerodata = A(:,2) == 0;
which will give you a logical array of ones and zeros like [1 1 1 0 1 0 0 ...]. Then you can use this to split up your input. You could look at the diff of that array and test it for positive or negative sign. Your data starts on 0 so you won't get a transition for that one, so you'd need to think of some way to deal with that or the opposite case, unless you know for certain that it will always be one way or the other. You could just test the first element, or you could insert a known value at the start of your input array.
You will then have to store your chunks. As they may be of variable length and variable number you wouldn't put them into a big matrix, but you still want to be able to use a loop. I would use either a cell array, where each cell in a row contains the x or y data for a chunk, or a struct array where say structarray(1).x and structarray)1).y hold your data values.
Then you can iterate through your struct array and call plot on each chunk separately.
As for fitting you can use the fit command. It's complex and has lots of options so you should check out the help first (type doc fit inside the console to get the inline help, which is the same as the website help in content). The short version is that you can do a simple linear fit like this
[fitobject, gof] = fit(x, y, 'poly1');
where 'poly1' specifies you want a first order polynomial (i.e. straight line) and the output arguments give you a fit object, which you can do various things with like plot or interpolate, and the second gives you a struct containing among other things the r^2 and adjusted r^2. The fitobject also contains your fit coefficients.

Calculating value y for each XI and XII in MATLAB:

I am currently working in matlab to design a way to reconstruct 3D data. For this I have two pictures with black points. The difference in the amount of points per frame is key for the reconstruction, but MATLAB gives an error when matrixes are not equal. This is happening becaus the code is not doing what I want it to do, so can anyone hel me with the following?
I have two columns of Xdata: XLI and XRI
What matlab does when I do XLI-XRI is substracting the pairs i.e XLI(1)-XRI(1) etc, but I want to substract each value of XRI of every value of XLI. i.e
XLI(1)-XRI(1,2,3,4 etc)
XLI(2)-XRI(1 2 3 4 etc)
and so on
Can anyone help?
I think you are looking for a way to deduct all combinations from eachother. Here is an example of how you can do that with bsxfun:
xLI = [1 2 3]
xRI = [1 2]
bsxfun(#minus,xLI ,xRI')
I cannot comment on Dennis's post (not enough points on this website) : his solution should work, but depending on your version of Matlab you might get a "Error using ==> bsxfun" and need to transpose either xLI or xRI for that to work :
bsxfun(#minus,xLI' ,xRI)
Best,
Tepp

Add node numbers/get node locations from MATLAB's treeplot

I have been working with MATLAB's treeplot function, but it seems to provide surprisingly little plotting functionality and/or extendibility.
I am plotting a tree like so:
tree = [0 1 2 2 2 2 2 1 8 8 1 11 11 1 14];
treeplot(tree)
Giving:
What I would like to do is add annotations or labels to specific nodes. A good starter would be to add the node numbers to each node, as in the example from the help file:
As they state, though:
These indices are shown only for the point of illustrating the example; they are not part of the treeplot output.
Is there a way to get the locations of the plotted nodes, or at the very least to plot the node numbers? I couldn't find any FEX submissions with more advanced tree plots.
Ultimately, I'd like to plot small pictures at the nodes (using methods from answers to a previous question of mine).
This should help you make a labeled tree:
(You supply the 'treeVec'.)
treeplot(treeVec);
count = size(treeVec,2);
[x,y] = treelayout(treeVec);
x = x';
y = y';
name1 = cellstr(num2str((1:count)'));
text(x(:,1), y(:,1), name1, 'VerticalAlignment','bottom','HorizontalAlignment','right')
title({'Level Lines'},'FontSize',12,'FontName','Times New Roman');
With your sample input, this gives
To get the position of the nodes, use treelayout
[x,y]=treelayout(tree);
The vectors x and y give you the positions, which you can then use to plot images at the nodes.