MATLAB - Labeling Curves During Iteration - matlab

I want to show the p value that was used to generate each curve next to each of the curves plotted. Note that since there is a plot of E and -E, the same p value should be next to both. I've been attempting this for a while and I have not come across anything super useful.
t = -3.1;%coupling
a = 1;%distance between r1 and r3
n = 5;%latice vector span in a1 direction
m = 1;%latice vector span in a2 direction
i = -7;%unique axial vector t_hat direction
j = 11;%unique axial vector c_hat direction
max_p = abs((n*(i+j/2)-j*(m+n/2)));%# of unique p values
La = sqrt(3)*sqrt(m^2+n*m+n^2)*a/gcd(2*n+m,2*m+n);%unit cell length
C = sqrt(n^2+n*m+m^2);%circumference of the nanotube
hold on;
for p=0:1:max_p
kt = -pi/La:.05:pi/La;
kc = 2*pi*p/C;
ka1 = kc*a*.5*(2*n+m)/C + kt*a*sqrt(3)*.5*m/C;
ka2 = kc*a*.5*(n+2*m)/C - kt*a*sqrt(3)*.5*n/C;
E = abs(t+t*exp(1i*ka2)+t*exp(1i*ka1));
title_ = sprintf('(%d,%d) Carbon Nanotube Dispersion Diagram',n,m);
title(title_);
xlabel('k_{t}a');
ylabel('Energy (eV)');
plot(kt,E);
plot(kt,-E);
end

There is a command named text that writes comments into the figures,
http://www.mathworks.se/help/techdoc/ref/text.html
with if you can't solve it with that and the to string operation i misunderstood the question

First, do you need to plot both E and -E? Since these are the same except for their sign you don't really add any information to the plot by having -E there as well. However, if you do need both lines, then just construct an array of strings for the legend, during the loop, which has each string included twice (once for E and once for -E).
... Initial calculations ...
hold on;
for p=0:1:max_p
kt = -pi/La:.05:pi/La;
kc = 2*pi*p/C;
ka1 = kc*a*.5*(2*n+m)/C + kt*a*sqrt(3)*.5*m/C;
ka2 = kc*a*.5*(n+2*m)/C - kt*a*sqrt(3)*.5*n/C;
E = abs(t+t*exp(1i*ka2)+t*exp(1i*ka1));
plot(kt,E);
plot(kt,-E);
% Construct array containing legend text
legend_text{2*(p+1)-1} = strcat('p=', num2str(p));
legend_text{2*(p+1)} = strcat('p=', num2str(p));
end
title_ = sprintf('(%d,%d) Carbon Nanotube Dispersion Diagram',n,m);
title(title_);
xlabel('k_{t}a');
ylabel('Energy (eV)');
legend(legend_text)
I am sure there is a more elegant way of constructing the legend text, but the above code works. Also, notice that I moved the calls to xlabel, ylabel and title to outside of the loop. This way they are only called once and not for each iteration of the loop.
Finally, you need to take care to ensure that each iteration of the loop plots with a different line colour or line style (see edit below). You could colour/style each pair of E and -E lines the same for a given iteration of the loop and just display the legend for E (or -E), which would obviously halve the number of legend entries. To do this you will need to hide one of line's handle visibility - this prevents it from getting an item in the legend. To do this use the following in your loop:
plot(kt, E);
plot(kt,-E, 'HandleVisibility', 'off');
% Construct array containing legend text
legend_text{p+1} = strcat('p=', num2str(p));
Finally, it is best to include clear all at the top of your Matlab scripts.
Edit: To have each plotted line use a different colour for each iteration of your loop use something like the following
... initial calculations ...
cmap = hsv(max_p); % Create a max_p-by-3 set of colors from the HSV colormap
hold on;
for p = 0:1:max_p
plot(kt, E, 'Color', cmap(p,:)); % Plot each pair of lines with a different color
plot(kt, -E, 'Color', cmap(p,:));
end

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 line in Matlab plot

I wrote a code plot 17 lines in the same graph. I want to label all line on the graph . Can u help me ?
clear all
close all
clc
syms w
wn=4000 %rad/s
k=1
for n=0:0.05:0.8
w=0:10:1884;
H=1./sqrt((1-(w/wn).^2)+(2*n*w/wn).^2);
x=w/wn
plot(x,H)
title('Time versus Response Graph of n');
xlabel('Time(s)');
ylabel('Response(m)');
k=k+1
hold on
end
I want to clariy which value is equal to which line.
That's usually done by annotation, and I think it is done manually. Since you have a lot of graphs and not much space, I suggest you use text to add the label at the end of the line. So in the loop add (under ylabel for example)
str = sprintf(' n = %.2f',n);
text(x(end),H(end),str);
This will result in
As you can see there is an overlap in the beginning because the curves are close to each other. You can hardcode a little offset for the first one as follows: (Annotation is graph dependent so I think it's ok to hardcode this)
if n == 0
text(x(end),H(end)+.005,str);
else
text(x(end),H(end),str);
end
Result:
General remarks on your code:
you don't use w symbolic so delete syms w
you don't use k so get rid of it as well
w and x can be moved outside the loop and w/wn can be replaced by x
You can also write this without a loop:
wn=4000; %rad/s
w=0:10:1884;
x=w/wn;
n=0:0.05:0.8;
N = length(n);
H=1./sqrt((1-(ones(N,1)*x).^2)+(2*n.'*x).^2);
plot(x,H)
title('Time versus Response Graph of n');
xlabel('Time(s)');
ylabel('Response(m)');
str = sprintf(' n = %.2f\t',n);
strs = strsplit(str,'\t');
offset = zeros(N,1);
offset(1)=.005;
offset(2)=.001;
text(x(end).*ones(N,1),H(:,end)+offset,strs(1:N));
This way it is easier to adjust the offsets of the different curves. (Note I've added an offset for the second curve as well leading to graph below)
`

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.

why cant i display both the colorbar's title and ticks simultaneously?

gamma=20;
P=0.1;
N=P.*gamma;
lamdazero=1550;
[lamdapump,lamdasignal] = meshgrid(1540:0.1:1580,1520:0.1:1580);
beta3=0.06;
beta4=-2*10^-4;
c=2*pi*3*10^8;
L=1;
A0=(1./lamdapump) -(1./lamdazero);
B0=(1./lamdapump) -(1./lamdasignal);
Third0=10^-9.*beta3.*(c.^3).*A0.*(B0.^2);
Fourth0=10^-12.*beta4.*(1./2).*c.^4.*(A0.^2).*(B0.^2);
Fourorder=(10^-12).*c.^4.*beta4.*(1/12).*(B0).^4;
deltabeta=Third0+Fourth0+Fourorder;
test2 = deltabeta;
test2(~(deltabeta<=0 & deltabeta>=-4*N)) = nan;
[C,h]=contourf(lamdapump,lamdasignal,test2,[-(4*N):N/2:0],'ShowText','off');
caxis([-8 0]);
xlabel('\lambda_p_u_m_p')
ylabel('\lambda_s_i_g_n_a_l')
title('Contour representing linear phase mismatch in terms of pump and signal wavelength ')
colorbar('YTickLabel',{'-4','-3.5','-3','-2.5','-2','-1.5','-1','-0.5','0'})
h2=colorbar;
HandleOfTitle = get(h2,'Title');
set(HandleOfTitle,'String','\Delta \beta (\gamma P_F_W_M)');
%If i remove the color yticklabel i get my colorbar title and viceversa
%need to know what to do
%The code works just fine
You are creating two colorbars, the second overwrites the first.
colorbar('YTickLabel',{'-4','-3.5','-3','-2.5','-2','-1.5','-1','-0.5','0'})
Creates a colorbar.
h2=colorbar;
Creates another colorbar and removes the first. Get the handle from the first call and remove the second:
h2 = colorbar('YTickLabel',{'-4','-3.5','-3','-2.5','-2','-1.5','-1','-0.5','0'});
Then use the handle to set the title as before.

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...