Matlab plot legend automation - matlab

I am solving a pde that depends on x and t and would like to show the solution over all x for a few values of t. I am trying to write code that will automatically generate a legend for this plot. For example, if I am plotting the solution at t = 0, 1, 5, and 9, I want the legend to show "t=0", "t=1", and so on.
Let's say my solution is held in matrix u. My times are held in vector t. The index of the times I am sampling would be in vector tsampled. Note this is not the same as the time I want on the plot. If I take the time at index 6 of vector t, this value is not 6, but could be anything.
I am currently attempting to do this by:
tlen = max(size(t));
tsampled = [2, floor(tlen/5), floor(2*tlen/5), floor(3*tlen/5), floor(4*tlen/5), floor(tlen)];
t(tsampled)
legnd = {'', '', '', '', '', ''};
hold on
for i = 1:1:size(tsampled)
plot(x,u(tsampled(i),:))
legnd(i) = sprintf('t = %0.2f s \n', t(tsampled(i)));
end
title('my PDE solution');
legend(legnd, 0);
xlabel('x')
ylabel('u')
hold off
But this is producing the error "Conversion to cell from char is not possible."
When I instead try using the line:
legend (sprintf('t = %0.2f s \n', t(tsampled)))
I get the correct "strings" on the graph, but they are formatted like this:
I would like this to show "t=10.20 s" next to a blue line, "t = 91.84 s" next to an orange line, and so on. How do I get the result I want?

Because you predefined legnd as a cell array, you need to use {} instead of () to get the correct index. Try:
legnd{i} = sprintf('t = %0.2f s \n', t(tsampled(i)));

Related

How can I build custom xticklabels using numbers and strings?

I am trying to customize the Xticklabels of my bar graph to have a format of 'number (units)'
So far I have a vector:
scanrate = [2;4;6;8;10];
I want my bar graph to have an x axis of:
2mv/s 4mv/s 6mv/s 8mv/s 10mv/s
If I use xticklabels(num2str(scanrate))
the xticklabels change to the numbers in the scanrate vector. I want to put mv/s after each Xtick.
You can also use strcat :
xticklabels(strcat(num2str(scanrate),' mv/s'))
Please note that it works only when scanrate is a column vector.
Fun fact :
num2str(scanrate) + " mv/s"
also works, but
num2str(scanrate) + ' mv/s'
does not
Build your strings using sprintf(), where the %d flag is for an unsigned integer:
my_labels = {};
for ii = 1:numel(scanrate)
my_labels{ii} = sprintf('%dmv/s', scanrate(ii));
end
figure;
% (...) make your plot
xticklabels(my_labels)
Alternative one-liner, thanks to Wolfie's comment:
my_labels = arrayfun(#(x)sprintf('%dmv/s',x),scanrate,'uni',0);
As a side note: that's normally not what you'd do when creating these type of plots. You'd just have numbers on the axes and a label stating something as "Velocity [mv/s]", rather than having the unit on every single tick label.

How to delete specific values from matrix in matlab

I have image matrix 420x700, and I want to delete a specific value in each row, changing the image dimensions. It is like deleting a column from it, but not in a straight line, to become 420x699 image. I should keep the values before the deleted value horizontally and shift all the values after it back by 1 position.
RGB = imread('image.jpg');
I1 = RGB(:,:,1);
How do I do that?
This is a good question, and I cannot think of a way to do this without a for-loop.
Let M be the nr-by-nc matrix from which you want to remove a column, and R the nr-by-1 vector with the column index of the element to be remove on each row.
The following code creates a new matrix A with the "column" removed from M, and vector B with the elements that were removed:
[nr,nc] = size(M);
A = zeros(nr,nc-1,'like',M);
B = zeros(nr,1,'like',M);
for k = 1:nr
r = R(k);
t = [ 1:r-1, r+1:nc ];
A(k,:) = M(k,t);
B(k) = M(k,r);
end
#beaker and #Cris are correct, but just to add some flavor to this, I've attempted to demonstrate an alternate method - using linear indexing, which can teach an interesting lesson on column major indexing of 2D arrays in MATLAB.
Another point to note is that this kind of process is what's followed in the seam carving algorithm, where we remove a vertical seam in this manner.
Load a test image to run this on - crop it to analyze easier.
I = imread('peppers.png');
I = I(100:100+9, 100:100+19, :);
figure, imshow(I)
Create a mask indicating which pixels are to be removed. This simulates the condition which I think you're pointing to - in this case, we choose random column indices for each row to be removed. You'd likely have this information as an input.
mask = zeros(size(I, [1:2]), 'logical');
for idx = 1:size(mask, 1)
randidx = randi(size(mask, 2));
mask(idx, randidx) = 1;
end
figure, imshow(mask)
Use the column major linear indexing trick to do the removal faster! Since we're removing a column at at time, we rotate the image 90 degrees, and translate this problem to removing one row at a time. MATLAB indexes 'vertically', and so we can then use linear indexing to simply remove the masked pixels all at once (rather than one row/column at a time), and then restore the shape using reshape, and finally rotate back to the original orientation.
It = rot90(I);
maskt = rot90(mask);
% Preallocate output
Ioutput = zeros([size(I, 1), size(I, 2) - 1, size(I, 3)], 'like', I);
for nchannel = 1:3
Icropped = It(:, :, nchannel);
% MATLAB indexes column wise - so, we can use linear indexing to make
% this computation simpler!
Icropped = Icropped(maskt(:) == 0);
Icropped = reshape(Icropped, [size(maskt, 1) - 1, size(maskt, 2)]);
% Restore the correct orientation after removing element!
Icropped = rot90(Icropped, 3);
Ioutput(:, :, nchannel) = Icropped;
end
figure, imshow(Ioutput)
I've cropped the 'peppers' image to demonstrate this, so that you can convince yourself that this is doing it right. This method should work similarly for larger images as well.

Using a colon for indexing in matrices of unknown dimensions

When indexing matrices in MATLAB, can I specify only the first or last n dimensions, and have all others dimensions "selected automatically"?
For example, I am writing a function which takes in an image, and displays it with imshow, which can either display a 3-D color image (e.g 1024×768×3) or a 2-D monochrome array (e.g 1024x768).
My function does not care about how many color channels the image has, imshow will take care of that. All I want to do is pass parameters to select a single region:
imshow(frame(x1:x2, y1:y2, :))
What do I put in place of the last colon to say "include all the others dimensions"?
You can use comma-separated-list expansion together with the ':' indexing.
Suppose your input is:
A = rand([7,4,2,3]);
To retrieve only first 2:
cln = {':', ':'};
A(cln{:})
To retrieve the last 3:
cln = {1, ':', ':', ':'};
A(cln{:})
Which can be generalized with:
sten = 2:3; % Which dims to retrieve
cln(1:ndims(A)) = {1};
cln(sten) = {':'};
A(cln{:})
Following from Oleg's answer, here is a function that will work if you are selecting from several of the first dimensions. If other dimensions are needed, I think you can see how to modify.
function [dat] = getblock2(dat, varargin)
%[dat] = getblock(dat, varargin) select subarray and retain all others
% unchanged
%dat2 = getblock(dat, [1,2], [3,5]) is equivalent to
% dat2 = dat(1:2, 3:5, :, :, :) etc.
%Peter Burns 4 June 2013
arg1(1:ndims(dat)) = {':,'};
v = cell2mat(varargin);
nv = length(v)/2;
v = reshape(v,2,nv)';
for ii=1:nv
arg1{ii} = [num2str(v(ii,1)),':',num2str(v(ii,2)),','];
end
arg2 = cell2mat(arg1);
arg2 = ['dat(',arg2(1:end-1),')'];
dat = eval(arg2);

MATLAB - Labeling Curves During Iteration

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

conversion from mathematica to matlab --> (appendto)

i have the following in mathematica and want to use it in matlab.I tried but i have mistakes and can't fixed them.It is that i don't get yet the matlab philosophy!
So,
intMC = {}; sigmat = {};
Do[np1 = np + i*100;
xpoints = Table[RandomReal[], {z1, 1, np1}];
a1t = Table[f[xpoints[[i2]]], {i2, 1, np1}];
a12 = StandardDeviation[a1t]/Sqrt[Length[a1t]];
AppendTo[intMC, {np1, Mean[a1t], a12}];
AppendTo[sigmat, {np1, a12}],
{i, 1, ntr}];
I did this:
fx=# (x) exp(-x.^2);
intmc=zeros();
sigmat=zeros();
for i=1:ntr
np1=np+i*100;
xpoints=randn(1,np1);
for k=1:np1
a1t=fx(xpoints(k))
end %--> until here it prints the results,but in the
%end it gives
% me a message " Attempted to access xpoints(2,:);
%index out of bounds because size(xpoints)=[1,200]
%and stops executing.
%a1t=fx(xpoints(k,:)) % -->I tried this instead of the above but
%a1t=bsxfun(#plus,k,1:ntr) % it doesn't work
a12=std(a1t)/sqrt(length(a1t))
intmc=intmc([np1 mean(a1t) a12],:) %--> i can't handle these 3 and
sigmat=sigmat([np1 a12 ],:) %as i said it stopped executing
end
In order to append a scalar to a Matlab array, you can call either array(end+1) = value or array = [array;value] (replace the semicolon with a comma if you want a 1-by-n array). The latter also works for appending arrays; to append arrays with the former, you'd call array(end+1:end:size(newArray,1),:) = newArray in case you want to catenate along the first dimension.
However, appending in loops that do more than, say, 100 iterations, is a bad idea in Matlab, because it is slow. You're better off pre-assigning the array first - or even better, vectorizing the computation so that you don't have to loop at all.
If I understand you correctly, you want to calculate mean and SEM from a growing number of samples from a normal distribution. Here's how you can do this with a loop:
intmc = zeros(ntr,3); %# stores, on each row, np1, mean, SEM
sigmat = zeros(ntr,2); %# stores, on each row, np1 and SEM
for i=1:ntr
%# draw np+100*i normally distributed random values
np1 = np+i*100;
xpoints = randn(np1,1);
%# if you want to use uniform random values (as in randomreal), use rand
%# Also, you can apply f(x) directly on the array xpoints
%# caculate mean, sem
m = mean(xpoints);
sem = std(xpoints)/sqrt(np1);
%# store
intmc(i,:) = [np1, m, sem];
sigmat(i,:) = [np1,sem];
end %# loop over i