how to use subplot within two loops - matlab

I need one figure with multiple graphs within two loops.
for i=1:length(state)
[block]
for j=1:length(channel)
[block]
subplot(length(state),length(channel)),j)
plot(a,b)% a and b are arrays of doubles.
end
end
I want one figure with size =length(state)*length(channel); for instance I need all the graphs of state(1)within all channels in the first row etc...
But what I get is multiple figures (the length of state).

If I understand well enough here is a way to do it :
figure()
lx = 2;
ly = 3;
for ii = 1:lx
for jj = 1:ly
subplot(lx,ly,ly*(ii-1)+jj)
plot(ii,jj,'o')
end
end
Why ly*(ii-1)+jj?
The syntax of subplot is the following : subplot(nbRows,nbCols,position) and the position is given by an unique index going over all available subplots (see image) which is ly*(ii-1)+jj.

Related

Title over a group of subplots

I want a figure with six plots inside; I split it with subplots. For example
for i = 1:12
subplot(3,4,i)
plot(peaks)
title(['Title plot ',num2str(i)])
end
I would like to add two global titles, let's say a global title for the six plots on the left hand side and another title for the six other plots on the right hand side.
I don't have 2018b version, so I cannot use sgtitle('Subplot Title');. Is it possible use suptitle('my title'); somehow?
I can use text() but resizing the window, the two labels move.
You can use annotation for that, with the location of subplots 1 and 3:
for k = 1:12
sp(k) = subplot(3,4,k);
plot(peaks)
title(['Title plot ',num2str(k)])
end
spPos = cat(1,sp([1 3]).Position);
titleSettings = {'HorizontalAlignment','center','EdgeColor','none','FontSize',18};
annotation('textbox','Position',[spPos(1,1:2) 0.3 0.3],'String','Left title',titleSettings{:})
annotation('textbox','Position',[spPos(2,1:2) 0.3 0.3],'String','Right title',titleSettings{:})
I did not test this, but you can get the handle to a subplot object and then perform the title method on this handle. I would also suggest to then apply the title after the loop.
CODE
for k = 1:12
h(k) = subplot(3, 4, i)
plot(peak)
end
title(h(1), 'Left side')
title(h(8), 'Right side') % find out the right index yourself
Remark:
Do not use i or j as iteration variable for they are already defined in the namespace of MATLAB as imaginary unit.

How to label graph edges with a loop?

I'm using a for loop to add more nodes and edges on my plot. However, when I add labels on new edges the old labels are removed. I don't know how to keep old edge-labels nor how to store the results of labeledge.
This is what I have got so far.
for r = 1: 10
for j = 1:10
H = addnode(P,nodeName{r}{j});
P = addedge(H, s{r}{j}, t{r}{j}, w{r}{j});
figure;
hold on;
h = plot(P);
labeledge(h,s{r}{j},t{r}{j},labelText{r}{j})
end
end
Every time in the new plot, I can only see the newest cluster of labels while old labels are gone. Ideally, I'd love to hold on the results of labeledge but hold on can't do this. I need to show labels in each step in the loop, thus adding another overall labeledge is not my ideal solution. Any hint would be appreciated.
Edit: All my variables are multiple cells of difference sizes in cell arrays. I use for loop to help to pick up vectors from cells because I don't know how to insert all the levels of information from such cell arrays of cells etc. into addNode function.
The main problem in your code is that you keep plotting the graph again and again. This isn't necessary. Instead, use one loop to create the graph object (G), then plot it all at once, and then use another loop for labeling the graph:
P = graph;
for r = 1: 10
for j = 1:10
P = addedge(P, s{r}{j}, t{r}{j}, w{r}{j});
end
end
h = plot(P);
for r = 1: 10
for j = 1:10
labeledge(h,s{r}{j},t{r}{j},labelText{r}{j})
end
end
If you wish to plot your graph on every iteration, you can use subgraph for that:
for k = 1:height(P.Nodes)
H = subgraph(P,1:k);
figure;
h = plot(H);
c = 1;
out = false;
for r = 1: 10
if ~out
for j = 1:10
if c < k
labeledge(h,c,labelText{r}{j})
else
out = true;
break
end
c = c+1;
end
else
break
end
end
end
Besides that, you should know that (from Matlab documentation):
For the best performance, construct graphs all at once using a single call to graph. Adding nodes or edges in a loop can be slow for large graphs.
Also, regardless of the above recommendation, for an easier manipulation of your data, you should first convert your cells to an array. If your cell array contains a different number of elements in each cell, then it is better to collapse it all to one column:
C = [s{:}]; % and the same for t and w
while any(cellfun(#iscell,C))
C = vertcat(C{:});
end
C = cellfun(#(x) x(:),C,'UniformOutput', false);
S = vertcat(C{:});
Labels = [labelText{:}]; % and the same nodeName
while any(cellfun(#iscell,Labels))
Labels = vertcat(Labels{:});
end
Try to remove the 'figure;' command out of the FOR loop and try to see if this worked.

Saving values of variable in MATLAB

Hi for my code I would like to know how to best save my variable column. column is 733x1. Ideally I would like to have
column1(y)=column, but I obtain the error:
Conversion to cell from logical is not possible.
in the inner loop. I find it difficult to access these stored values in overlap.
for i = 1:7
for y = 1:ydim % ydim = 436
%execute code %code produces different 'column' on each iteration
column1{y} = column; %'column' size 733x1 %altogether 436 sets of 'column'
end
overlap{i} = column1; %iterates 7 times.
end
Ideally I want overlap to store 7 variables saved that are (733x436).
Thanks.
I'm assuming column is calculated using a procedure where each column is dependent on the latter. If not, then there are very likely improvements that can be made to this:
column = zeros(733, 1); % Might not need this. Depends on you code.
all_columns = zeros(xdim, ydim); % Pre-allocate memory (always do this)
% Note that the first dimension is usually called x,
% and the second called y in MATLAB
overlap = cell(7, 1);
overlap(:) = {zeros(xdim, ydim)}; % Pre-allocate memory
for ii = 1:numel(overlap) % numel is better than length
for jj = 1:ydim % ii and jj are better than i and j
% several_lines_of_code_to_calculate_column
column = something;
all_columns(:, jj) = column;
end
overlap{ii} = all_columns;
end
You can access the variables in overlap like this: overlap{1}(1,1);. This will get the first element in the first cell. overlap{2} will get the entire matrix in the second cell.
You specified that you wanted 7 variables. Your code implies that you know that cells are better than assigning it to different variables (var1, var2 ...). Good! The solution with different variables is bad bad bad.
Instead of using a cell array, you could instead use a 3D-array. This might make processing later on faster, if you can vectorize stuff for instance.
This will be:
column = zeros(733, 1); % Might not need this. Depends on you code.
overlap = zeros(xdim, ydim, 7) % Pre-allocate memory for 3D-matrix
for ii = 1:7
for jj = 1:ydim
% several_lines_of_code_to_calculate_column
column = something;
all_column(:, jj, ii) = column;
end
end

Creating a scatter plot in matlab with different colors and markers for two different grouping variables

I seem to be having problems creating a 2D scatter plot in matlab with two grouping variables which displays different colors for one of them and different markers for the other. The variable "score" has the X and Y values and the two grouping variables are "att21" and "att22".
I use the following code:
f=figure;
gscatter(score(:,1), score(:,2), {att21, att22}, 'br', 'xo');
what I'm getting is:
scatter plot
However, what I want to get is blue for L4 and red for L1 and x for Flake and o for Chunk. I would also like the legend to indicate this.
What am I missing?
Thanks for any help...
OK, I think I figured it out. The solution provided by Noel is good only if I know the number of groups in each grouping variable, but unfortunately this is not the case.
So I came up with the solution if using nested loops.
f=figure;
hold on;
marker = '+o*.xsd';
clr = 'rgbymck';
att1v = unique(att1);
att2v = unique(att2);
attv = [att1v; att2v];
att1count = 1;
att2count = 1;
for k=1:length(score)
att1count = 1;
att2count = 1;
while att1count <= length(att1v)
if isequal(att1(k),att1v(att1count))
while att2count <= length(att2v)
if isequal(att2(k),att2v(att2count))
f=scatter(score(k,1),score(k,2),15,clr(att1count),marker(att2count));
end
att2count = att2count + 1;
end
end
att1count = att1count + 1;
end
end
legend(attv);
Now the scatter plot is OK and its supports up to 7 groups in each variable. The only problem I'm left with is that I can't manage to create a Legend which shows the different labels for all the groups.
All I manage to get is this:plot with bad legend
If anyone has a solution for me it will be great...
Thanks alot
When you are grouping by 2 grouping variables, each with 2 categories, you are implicitly creating 4 different groups, so you have to define the color and markers for the 4 groups, in your case
gscatter(score(:,1), score(:,2), {att21, att22}, 'rrbb', 'xoxo');
But since gscatter will repeat the pattern if the defined color or marker is smaller than the number of groups, you can save 2 characters by doing
gscatter(score(:,1), score(:,2), {att21, att22}, 'rrbb', 'xo');
If you don't know the number of groups in each category, you can obtain them with the command unique and count them, and then use that number to create the markers and colors. For your example
marker = '+o*.xsd';
clr = 'rgbymck';
n_groups_att1 = length(unique(att21));
n_groups_att2 = length(unique(att22));
m = marker(1:n_groups_att2);
c = repmat(clr(1:n_groups_att1),n_groups_att2,1);
c = c(:)';
gscatter(score(:,1), score(:,2), {att21, att22}, c, m);
Just make sure that marker and clr has more elements than possible number of groups in each grouping variable

Matlab: Random sample with replacement

What is the best way to do random sample with replacement from dataset? I am using 316 * 34 as my dataset. I want to segment the data into three buckets but with replacement. Should I use the randperm because I need to make sure I keep the index intact where that index would be handy in identifying the label data. I am new to matlab I saw there are couple of random sample methods but they didn't look like its doing what I am looking for, its strange to think that something like doesn't exist in matlab, but I did the follwoing:
My issue is when I do this row_idx = round(rand(1)*316) sometimes I get zero, that leads to two questions
what should I do to avoid zeor?
What is the best way to do the random sample with replacement.
shuffle_X = X(randperm(size(X,1)),:);
lengthOf_shuffle_X = length(shuffle_X)
number_of_rows_per_bucket = round(lengthOf_shuffle_X / 3)
bucket_cell = cell(3,1)
bag_matrix = []
for k = 1:length(bucket_cell)
for i = 1:number_of_rows_per_bucket
row_idx = round(rand(1)*316)
bag_matrix(i,:) = shuffle_X(row_idx,:)
end
bucket_cell{k} = bag_matrix
end
I could do following:
if row_idx == 0
row_idx = round(rand(1)*316)
assuming random number will never give two zeros values in two consecutive rounds.
randi is a good way to get integer indices for sampling with replacement. Assuming you want to fill three buckets with an equal number of samples, then you can write
data = rand(316,34); %# create some dummy data
number_of_data = size(data,1);
number_of_rows_per_bucket = 50;
bucket_cell = cell(1,3);
idx = randi([1,number_of_data],[number_of_rows_per_bucket,3]);
for iBucket = 1:3
bucket_cell{iBucket} = data(idx(:,iBucket),:);
end
To the question: if you use randperm it will give you a draw order without replacement, since you can draw any item once.
If you use randi it draws you with replacement, that is you draw an item possibly many times.
If you want to "segment" a dataset, that usually means you split the dataset into three distinct sets. For that you use draw without replacement (you don't put the items back; use randperm). If you'd do it with replacement (using randi), it will be incredibly slow, since after some time the chance that you draw an item which you have not before is very low.
(Details in coupon collector ).
If you need a segmentation that is a split, you can just go over the elements and independently decide where to put it. (That is you choose a bucket for each item with replacement -- that is you put any chosen bucket back into the game.)
For that:
% if your data items are vectors say data = [1 1; 2 2; 3 3; 4 4]
num_data = length(data);
bucket_labels = randi(3,[1,num_data]); % draw a bucket label for each item, independently.
for i=1:3
bucket{i} = data(bucket_labels==i,:);
end
%if your data items are scalars say data = [1 2 3 4 5]
num_data = length(data);
bucket_labels = randi(3,[1,num_data]);
for i=1:3
bucket{i} = data(bucket_labels==i);
end
there we go.