I have a 2 column matrix(called M, which I visualize as two vectors using Matlab's plot command(plot(M)). I have two issues:
I want to label the vectors themselves on the plot.
I want to label each row of the matrix(i.e. each vector component) on the plot.
How would I go about doing those things?
An example:
M = cumsum(rand(10,2) - 0.5);
x = 1:size(M,1);
plot(x, M(:,1), 'b.-', x, M(:,2), 'g.-')
legend('M1', 'M2')
for i=x
text(i+0.1, M(i,1), sprintf('%.2f', M(i,1)), 'FontSize',7, 'Color','b');
text(i+0.1, M(i,2), sprintf('%.2f', M(i,2)), 'FontSize',7, 'Color','g');
end
Alternatively, you can use:
datacursormode()
which will enable the user to just point and click on points to see the data labels.
You may need to tweak this to get the positions of the labels exactly how you want them, but something like this will do the trick.
M = [1 2; 3 4; 5 6]
plot(M)
nrows = size(M, 1);
ncols = size(M, 2);
x = repmat(nrows - .3, 1, ncols);
y = M(end, :) - .3;
labels = cellstr([repmat('Col', ncols, 1), num2str((1:ncols)')]);
text(x, y, labels)
You can label each axis with the function:
xlabel('label')
ylabel('label')
These can also take cell arguments, where each row is a new line. That's handy for showing units. Labeling each point on the figure can be done as so:
for i=1:length(M)
text(M(i,1),M(i,2),'Label Text')
end
The label text can also be a string variable that you can edit with sprintf and make special strings for each point.
Related
I couldn't find a good solution for this:
I have a matrix of this size: 60x10x3
And I want to transform it into a matrix of this size: 600x3
Basically I want to stack the 10 matrices with the dimension 60x3 next to each other in the first dimension.
How can I achieve that elegantly in matlab?
It seems that I don't understand what the intended output is, but here are two different ways to achieve it. I added the loop to create different numbers so the results can be studied.
Method 1 - Stack Vertically or Horizontally
s = zeros(60,10,3);
for x = 1:9
s(:,x,:) = x;
end
t = reshape(s, 600, 3); %vert
u = t'; %hori
Method 2 - Stack 3rd dimension Vertically or horizontally
s = zeros(60,10,3);
for x = 1:9
s(:,x,:) = x;
end
t = [s(:,:,1) , s(:,:,2), s(:,:,3)]; % hori
t = [s(:,:,1) ; s(:,:,2); s(:,:,3)]; % vert
Hope it helps, but this shows that there are multiple ways to achieve the same output in Matlab. Very powerful tool indeed.
A = rand(60, 10, 3);
B = reshape(A, [], size(A, 3));
should work for any dimensions of A.
Here is a solution that
stack[s] the 10 matrices with the dimension 60x3 next to each other in the first dimension.
a = rand(60,3,10);
% swap the 2nd and 3rd dimention
b = permute(a,[1,3,2]);
% condense to 2d
c = b(:,:);
% reshape x, y and z seperately so each group of 60 xs/ys/zs appends to the end of the previous group
x=reshape(c(:,1:3:end),[],1);
y=reshape(c(:,2:3:end),[],1);
z=reshape(c(:,3:3:end),[],1);
% condense to one 600*3 matrix
d = [x y z];
this might come as an eco in this forum but I couldn't find a solution that I could apply to my problem. I have a cell of res_A1 of size (1x500) and in each cell there is a vector (1xlength) where length varies. I would like to plot in the same graph every vector or maybe a handful of them. All lines can be in the same color. I have tried following but the graph make no sense
data=res_A1(1,:,end);
plot(cell2mat(data)');
Also I would like to plot the average of the 500 vectors, preferably this should be in the same graph in another color. Is there a nice way of doing this?
You can use cat to combine the vectors along the first dimension. Then you can pass the transpose of this matrix to plot and each column will be plotted as it's own plot.
plot(cat(1, data{:}).');
If we create some example data, this will yield.
data = arrayfun(#(x)rand(1,10), ones(1, 5), 'uni', 0);
plot(cat(1, data{:}).');
If you want specific ones (i.e. [1 3 5]), you can replace : above with the indices of the ones you want.
plot(cat(1, data{[1 3 5]}).');
If you want to plot the average, simply use mean on the result of the call to cat.
avg = mean(cat(1, data{:}), 1);
plot(avg);
And if you wanted it in the same plot:
alldata = cat(1, data{:});
avg = mean(alldata, 1);
% Plot all of the curves
plot(alldata.');
hold on
% Plot the average curve
plot(avg, 'LineWidth', 3, 'Color', [0.5 0.5 0.5], 'LineStyle', '--')
Update
If your data is all different lengths, You have two options, you could plot everything with a loop.
hax = axes;
hold(hax, 'on');
for k = 1:numel(data)
plot(data{k}, 'Parent', hax);
end
Or you could still try to combine everything into one matrix, padding with NaN values.
% Find the longest vector length
maxlength = max(cellfun(#(x)numel(x), data));
alldata = nan(maxlength, numel(data));
for k = 1:numel(data)
alldata(1:numel(data{k}),k) = data{k};
end
Then you can plot this and take the mean using nanmean.
plot(alldata);
avg = nanmean(alldata, 2);
Generate a plot showing the graphs of
y=(2*a+1)*exp(-x)-(a+1)*exp(2*x)
in the range x ∈ <-2, 4> for all integer values of a between -3 and 3
I know how to make typical plot for 2 values and set a range on the axes, but how to draw the graph dependent on the parameter a?
To elaborate on Ben Voigt's comment: A more advanced technique would be to replace the for-loop with a call to bsxfun to generate a matrix of evaluations of M(i,j) = f(x(i),a(j)) and call plot with this matrix. Matlab will then use the columns of the matrix and plot each column with individual colors.
%%// Create a function handle of your function
f = #(x,a) (2*a+1)*exp(-x)-(a+1)*exp(2*x);
%%// Plot the data
x = linspace(-2, 4);
as = -3:3;
plot(x, bsxfun(f,x(:),as));
%%// Add a legend
legendTexts = arrayfun(#(a) sprintf('a == %d', a), as, 'uni', 0);
legend(legendTexts, 'Location', 'best');
You could also create the evaluation matrix using ndgrid, which explicitly returns all combinations of the values of x and as. Here you have to pay closer attention on properly vectorizing the code. (We were lucky that the bsxfun approach worked without having to change the original f.)
f = #(x,a) (2*a+1).*exp(-x)-(a+1).*exp(2*x); %// Note the added dots.
[X,As] = ndgrid(x,as);
plot(x, f(X,As))
However for starters, you should get familiar with loops.
You can do it using a simple for loop as follows. You basically loop through each value of a and plot the corresponding y function.
clear
clc
close all
x = -2:4;
%// Define a
a = -3:3;
%// Counter for legend
p = 1;
LegendText = cell(1,numel(a));
figure;
hold on %// Important to keep all the lines on the same plot.
for k = a
CurrColor = rand(1,3);
y= (2*k+1).*exp(-x)-(k+1).*exp(2.*x);
plot(x,y,'Color',CurrColor);
%// Text for legend
LegendText{p} = sprintf('a equals %d',k);
p = p+1;
end
legend(LegendText,'Location','best')
Which gives something like this:
You can customize the graph as you like. Hope that helps get you started!
I often need to plot 10 images together, but using this code results in small images :
img = rand(400,600);
for i=1:10
subplot(2,5,i);
imshow(img);
title(['Image ' int2str(i)]);
end
As you can see, the images do not use all available space in the screen. How can I increase the size, or decrease the padding/margin between them?
Thanks for any help.
I don't believe there is an easy way to do it. There are two options:
First, use the position part of the subplot:
>> subplot(2,5, i, [l, b, w, h])
and calculate the left, bottom, width, height.
Or, get the handle of the returned axis:
>> h(i) = subplot(2,5,i);
and then modify the axis afterward.
>> set(h(1), 'position', [l, b, w, h] );
There are a number of pages that will give more detail, e.g., http://www.briandalessandro.com/blog/how-to-make-a-borderless-subplot-of-images-in-matlab/
[update]
The code below gives a little more detail on who you can do something like what you are looking for. It is a tad tedious. The 0.95 and 0.02 are just to give a little padding. They are nothing magical. :-)
One other thing to note is I would really encourage you to use "ii" as your index variable (or something else) as "i" is defined as sqrt(-1). It is a good convention not to use "i" and "j" as index variables (especially in Matlab).
img = rand(400,600);
figure(1);
clf();
hold on;
% Get the width and height of the figure
lbwh = get(1, 'position');
figw = lbwh(3);
figh = lbwh(4);
% Number of rows and columns of axes
ncols = 5;
nrows = 2;
% w and h of each axis in normalized units
axisw = (1 / ncols) * 0.95
axish = (1 / nrows) * 0.95
for ii=1:10
% calculate the row and column of the subplot
row = floor( ii/(ncols+1) ) + 1
col = mod( ii-1, ncols ) + 1
% calculate the left, bottom coordinate of this subplot
axisl = (axisw+0.02) * (col-1)
axisb = (axish+0.02) * (row-1)
% plot the subplot
h= subplot('position', [axisl, axisb, axisw, axish] );
imshow(img);
title(['Image ' int2str(ii)]);
pause
end
You will have to play with it to make it do exactly what you want. And "help" is your friend.
I have this requirement often and the most efficient way for me to achieve it is using the third party subplot_tight function, which is a more-or-less slot-in replacement for subplot. At its simplest you can do
figure(1); clf
subplot_tight(1,2,1, [0.05 0.05])
%normal plot stuff
where the two parameters in the fourth argument control the fraction of visible space around the image.
Based on the answer of #brechmos, when your subplot number is more than 10 subplot, then his code will trigger a error.
% calculate the row and column of the subplot
row = floor( ii/(ncols+1) ) + 1
col = mod( ii-1, ncols ) + 1
e.g. 4X5 cells, then subplot 11 will be wrongly interpreted as (2, 1), but not (3,1).
Replace it with the code below can fix it:
% calculate current row and column of the subplot
row = floor( (i-0.5)/ncols ) + 1;
col = mod(i-(row-1)*ncols, ncols+1);
You can use figure properties option once you generate the plot. Click on the subplot which you want to resize. From property editor select 'more properties' option. There if you scroll you will see 'Position' tab. You can change those values to see how the subplot moves and thus adjust subplot according to your preference.
Hi i'm having a problem where I have a dataset which ranges between -10^3 to 10^3
I need to be able to plot this as with a log scale but semilogy cannot plot negative values
Say for example my data is:
x = [-3,-2,-1,0,1,2,3];
y = [-1000,-100,-10,1,10,100,1000];
(or in general y=sign(x).*10.^abs(x);)
How can I plot this in MATLAB with a log scale? If possible It would be great if the log scale ticks could be on the Y-axis too
Use your actual data as labels, but scale the plotted data with log10.
% data
x = -3:0.1:3;
y = sign(x).*10.^abs(x);
% scaling function
scale = #(x) sign(x).*log10(abs(x));
N = 7; % number of ticks desired
% picking of adequate values for the labels
TickMask = linspace(1,numel(y),N);
YTickLabels = y(TickMask);
% scale labels and plotdata, remove NaN ->inconsistency, do you really want that?
YTick = scale( YTickLabels );
Y = scale(y);
YTick(isnan(YTick)) = 0;
Y(isnan(Y)) = 0;
% plot
plot(x,Y)
set(gca,'YTick',YTick,'YTickLabels',YTickLabels)
grid on
For N = 7:
For N = 11
How to find a valid value for N?
The following function (thanks to gnovice) will return all possible values you could choose for N:
n = numel(x);
N = find(rem(n./(1:n), 1) == 0) + 1;
about the semilogy-style labels: by adding the following line before the plot:
YTickLabels = cellfun(#(x) ['10^' num2str(x)], num2cell(YTick),'UniformOutput',false)
you could at least achieve something like this:
not beautiful and not generic, but a good point to start for you.
The reason you can't make a logarithmic axis that crosses zero, is that it doesn't make sense!
Since a logarithmic scale is generally displayed as eg. 100 - 10 - 1 - 1/10 - 1/100 - ..., you would need an infinite amount of space to make the axis cross zero.
How about this:
x=logspace(-3,3);
y=sign(x).*10.^abs(x);
loglog(x,y)
#thewaywewalk has already given a beautiful solution to it. The one I'm suggesting is an epsilon improvement on it. If you make two changes
(a) Define a new MATLAB function signia that basically extracts the sign before a number.
function value = signia(x)
if(x>=0)
value = '';
else
value = '-';
end
and (b) make this little change that instead of
YTickLabels = cellfun(#(x) ['10^' num2str(x)], num2cell(YTick),'UniformOutput',false)
you use
YTickLabels = cellfun(#(x) [signia(x) '10^{' num2str(x) '}'], num2cell(YTick),'UniformOutput',false);
(notice the presence of curly braces), you'll get an improvement in the Y ticks display. I got the following.
enter image description here