subplots for a combination of cell arrays - matlab

I am attempting to generate a figure with several subplots, e.g.
time = 1:365;
data = {rand(365,1),rand(365,1),rand(365,1)};
data2 = {rand(365,1),rand(365,1),rand(365,1)};
figure(1);
for i = 1:length(data);
for ii = 1:2:2*length(data);
for jj = 2:2:2*length(data);
subplot(5,2,ii);
plot(time,data{i});
subplot(5,2,jj);
plot(time,data2{i});
end
end
end
From this code I was trying to generate a subplot for each cell in 'data' and 'data2' where each of the cells in 'data' were plotted in subplots 1,3,5 and those in 'data2' in subplots 2,4,6. The code that I generate reproduces the same figure in all of the subplots for data and data2 instead of what I described above. I'm guessing the problem here is that the number of cells in each data set is 3 and the loop runs over 6 iterations? How can i fix this?

Try this. You don't need this nested loop there...
figure(1);
for i = 1:length(data);
subplot(5,2,(i-1)*2+1);
plot(time,data{i});
subplot(5,2,(i-1)*2+2);
plot(time,data2{i});
end

Related

Is there a way to give different titles to MATLAB figures being plotted inside a loop?

I am struggling to get different titles in each of my plots, below is my code and the error I keep getting:
code:
figure(5)
tiledlayout(2,3)
titles = ['0.1mm' '1mm' '2mm' '3mm' '4mm' '5mm'];
for i=1:length(L_PsiI1)
Psi_array2 = L_PsiI1(i)*I_array;
nexttile
plot(I_array, Psi_array2)
xlabel('Current (A)')
ylabel('Flux (Wb)')
grid on
title(titles(i))
end
error:
Index exceeds the number of array elements (14).
The code works perfectly fine when I comment out the title(titles(i)) line. I have also tried methods such as title(['Psi-I diagram ' num2str(i)]) and title(sprintf('Psi-I diagram %d',i)) as suggested by others. Many thanks to anyone who can help.
Convert the titles matrix to a cell by replacing the square brackets with curly brackets.
figure(5)
tiledlayout(2,3)
titles = {'0.1mm' '1mm' '2mm' '3mm' '4mm' '5mm'};
for i=1:6
%Psi_array2 = L_PsiI1(i)*I_array;
nexttile
plot([1:10], [1:10])
xlabel('Current (A)')
ylabel('Flux (Wb)')
grid on
title(titles(i))
end

how to use subplot within two loops

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.

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.

Legend in Matlab Plotting

I have some issues with the legends. I am trying to plot using this code and the code is this:
function PlotNormalPlot(z,i)
hold on
plotTypes = {'b', 'm', 'c'};
TrancheRange = {'100','1000','10000'};
h = normplot(z);
set(h,'color',plotTypes{i})
xlabel('Estimate')
ylabel('Probability')
legendInfo{i} = TrancheRange{i};
legend(legendInfo);
end
It is giving me this error:
Error using legend>process_inputs (line 552)
Cell array argument must be a cell array of strings.
Not sure why this error is there? Need some guidance.
EDIT:
When i tried this:
function PlotNormalPlot(z,i)
hold on
plotTypes = {'b', 'm', 'c'};
TrancheRange = {'100','1000','10000'};
h = normplot(z);
set(h,'color',plotTypes{i})
xlabel('Estimate')
ylabel('Probability')
%legendInfo = TrancheRange{i};
legend(TrancheRange);
end
The legend came out well but the color doesn't get attached to the legend. Not sure why.
Looks like this now:
Try legendInfo=TrancheRange{i}, so legendInfo is a single string.
legendInfo{i} will create a cell array, and, for i=2 as an example, would give you legendInfo={[] '2'} where the first element of legendInfo is an empty array.
I think this could answer your second question. It saves the legend information with the plot handle:
h = normplot(z);
set(h,'color',plotTypes{i},'DisplayName',TrancheRange{i})
legend(h,'show')

Most efficient way of drawing grouped boxplot matlab

I have 3 vectors: Y=rand(1000,1), X=Y-rand(1000,1) and ACTid=randi(6,1000,1).
I'd like to create boxplots by groups of Y and X corresponding to their group value 1:6 (from ACTid).
This is rather ad-hoc and looks nasty
for ii=
dummyY(ii)={Y(ACTid==ii)};
dummyX(ii)={X(ACTid==ii)}
end
Now I have the data in a cell but can't work out how to group it in a boxplot. Any thoughts?
I've found aboxplot function that looks like this but I don't want that, I'd like the builtin boxplot function because i'm converting it to matlab2tikz and this one doesn't do it well.
EDIT
Thanks to Oleg: we now have a grouped boxplot... but the labels are all skew-whiff.
xylabel = repmat({'Bleh','Blah'},1000,1); % need a legend instead, but doesn't appear possible
boxplot([Y(:,end); cfu], {repmat(ACTid,2,1), xylabel(:)} ,'factorgap',10,'color','rk')
set(gca,'xtick',1.5:3.2:50)
set(gca,'xticklabel',{'Direct care','Housekeeping','Mealtimes','Medication','Miscellaneous','Personal care'})
>> ylabel('Raw CFU counts (Y)')
How to add a legend?
I had the same problem with grouping data in a box plot. A further constraint of mine was that different groups have different amounts of data points. Based on a tutorial I found, this seems to be a nice solution I wanted to share with you:
x = [1,2,3,4,5,1,2,3,4,6];
group = [1,1,2,2,2,3,3,3,4,4];
positions = [1 1.25 2 2.25];
boxplot(x,group, 'positions', positions);
set(gca,'xtick',[mean(positions(1:2)) mean(positions(3:4)) ])
set(gca,'xticklabel',{'Direct care','Housekeeping'})
color = ['c', 'y', 'c', 'y'];
h = findobj(gca,'Tag','Box');
for j=1:length(h)
patch(get(h(j),'XData'),get(h(j),'YData'),color(j),'FaceAlpha',.5);
end
c = get(gca, 'Children');
hleg1 = legend(c(1:2), 'Feature1', 'Feature2' );
Here is a link to the tutorial.
A two-line approach (although if you want to retain two-line xlables and center those in the first line, it's gonna be hackish):
Y = rand(1000,1);
X = Y-rand(1000,1);
ACTid = randi(6,1000,1);
xylabel = repmat('xy',1000,1);
boxplot([X; Y], {repmat(ACTid,2,1), xylabel(:)} ,'factorgap',10)
The result:
EDIT
To center labels...
% Retrieve handles to text labels
h = allchild(findall(gca,'type','hggroup'));
% Delete x, y labels
throw = findobj(h,'string','x','-or','string','y');
h = setdiff(h,throw);
delete(throw);
% Center labels
mylbl = {'this','is','a','pain','in...','guess!'};
hlbl = findall(h,'type','text');
pos = cell2mat(get(hlbl,'pos'));
% New centered position for first intra-group label
newPos = num2cell([mean(reshape(pos(:,1),2,[]))' pos(1:2:end,2:end)],2);
set(hlbl(1:2:end),{'pos'},newPos,{'string'},mylbl')
% delete second intra-group label
delete(hlbl(2:2:end))
Exporting as .png will cause problems...