Labeling points on the x axis in matlab - matlab

I have a table, named "Log_mean" a quick example of this:
numberID
Score
Model
1
0.3
a
2
0.2
b
I have Plotted the ID against score using the following code:
plot(Log_mean.numberID, Log_mean.Score, '--o');
title('Mean of Log scores.')
ylabel('Score')
xlabel('Models')
Which produces the following graph:
My question is, as each circle represents the score for a particular model, is it possible for me to name each of those points on the x-axis using the column model in my table?
Thank you.

Yes, you just need a categorical axis
xlabs = categorical( Log_mean.Model, Log_mean.Model ); % using the 2nd input preserves ordering
Then you can plot it
plot( xlabs, Log_mean.Score, '--o' );
If you want to combine the model and the ID, you can do that a number of ways. Something like this would work:
xlabs = arrayfun( #(x) sprintf('%d - %s', Log_mean.numberID(x), Log_mean.Model{x}), 1:height(Log_mean), 'uni', 0 );
xlabs = categorical( xlabs, xlabs );
plot( xlabs, Log_mean.Score, '--o' );

Related

How to use stings as ticks on plots?

If both the x and y axis are numbers, I can display text on the plot by using the functions num2str, cellstr, and strtrim. These functions format the coordinate values into a cell array of strings, which can then be displayed with the function text:
strValues = strtrim(cellstr(num2str(
[X(:) Y(:)],
'(%d,%d)'
)));
text(
X,
Y,
strValues,
'VerticalAlignment',
'bottom'
);
But what if the x axis contains strings instead of numbers?
X=['john' 'jack' 'mary'.....]
Y=[0 1 2 3]
How do I then show the y values on all of the data plots?
You can create the plot with categoricals...
X = categorical( {'john','jack','mary','jack'} );
Y = [1 2 3 3];
figure;
plot( X, Y, '.', 'markersize', 20 );
You can then place text the same as with numeric data
text( categorical({'jack'}), 2, 'test' )
To add the value as a label to all the points, you can use X directly:
text( X, Y + 0.2, cellstr( num2str( Y(:) ) ) )
1st way:
Juse normal plotting (you may need to enumerate your categories first though) and than set the ticks of your axis. This allows maximum flexiblity at the cost of a potential mix-up
set(gca, 'xTick',1:length(X), 'xTickLabel',X)
The first ensures that all ticks are plottet while the second name-value-pair renames those ticks. When it comes to names or longer strings, you may also want to rotate the ticks labels with 'xtickangle'.
The MathWorks uses this workaround even in its examples:
x = linspace(-10,10,200);
y = cos(x);
plot(x,y)
xticks([-3*pi -2*pi -pi 0 pi 2*pi 3*pi])
xticklabels({'-3\pi','-2\pi','-\pi','0','\pi','2\pi','3\pi'})
2nd way: If you have categorial data, you can plot it right away. Have a look at the doc here.

MATLAB Plot - Legend entry for multiple data rows - getcolumn

Consider the following example:
x = magic(3);
figure(1); clf(1);
plot( x, '-r', 'DisplayName', 'Magic' );
legend( 'show' );
The resulting legend entries in MATLAB R2014a are
getcolumn(Magic,1)
getcolumn(Magic,2)
getcolumn(Magic,3)
The problem stems from function [leg,labelhandles,outH,outM] = legend(varargin) in legend.m (Copyright 1984-2012 The MathWorks, Inc.), line 628:
str{k} = get(ch(k),'DisplayName');
More specifically, the function get
prepends getcolumn( and
appends , <Column Number>).
Is there an easy way to display exactly one legend entry (or multiple, but without the pre- and appended strings) for multiple data rows named after DisplayName, which have the same visual properties?
An alternative would of course be to programatically create multiple (or one) legend entries through plot handles (see below), but I would like to keep things short and simple.
One entry:
x = magic(3);
figure(1); clf(1);
h = plot( x, '-r' );
legend( h(1), 'Magic' );
Multiple entries:
x = magic(3);
figure(1); clf(1);
h = plot( x, '-r' );
strL = cell( 1, numel(h) );
for k = 1:numel(h)
strL{k} = sprintf( 'Magic %d', k );
end
legend( h, strL );
In MATLAB R2014b, the problem with getcolumn(Name,Row) does not appear anymore for the first code example.
If you want to set multiple display names for the legend entries in short syntax, you just need to prepare a cell array with them, let's say it's called leg_names, and then use set to apply them to all at once:
set(p,{'DisplayName'},leg_names);
Let's take a look at an example:
x = magic(3); % your data
p = plot( x,'-r'); % plot and get an array of handles to the lines
% create a list of the desired names for the legend entries:
leg_names = [repmat('Magic ',size(x,2),1) num2str((1:size(x,2)).')];
set(p,{'DisplayName'},cellstr(leg_names)); % set all display names
legend('show'); % show the legend
The result is exactly as in your examples at the end of the question.
Also, note that the syntax: [lgd,icons,plots,txt] = legend(___) is not recommended (from the docs):
Note: This syntax is not recommended. It creates a legend that does not support all graphics features. Instead, use the lgd = legend(__) syntax to return the Legend object and set Legend Properties.

draw a line of best fit through data with shaded region for error

I have the following data:
dat = [9.3,0.6,0.4,0.7;...
3.2,1.2,0.7,1.9;...
3.9,1.8,0.7,1.9;...
1.0,7.4,5.6,10.7;...
4.7,1.0,0.5,1.3;...
2.2,2.6,1.2,2.7;...
7.2,1.0,0.5,1.1;...
1.0,4.8,7.5,10.3;...
2.7,1.8,1.7,4.0;...
8.2,0.8,0.4,0.9;...
1.0,4.9,5.7,8.2;...
12.9,1.3,0.6,1.6;...
7.7,0.8,0.5,1.3;...
5.8,0.9,0.6,1.9;...
1.1,4.5,6.2,12.1;...
1.1,4.5,2.8,4.8;...
16.4,0.3,0.3,0.5;...
10.4,0.6,0.3,0.7;...
2.2,3.1,2.2,4.6];
where the first column shows the observed values the second column shows the modeled values and the third and fourth columns show the min and max respectively.
I can plot the relationship between observed and modeled by
scatter(d(:,1),d(:,2))
Next, I would like to draw a smooth line through these points to show the relationship. How can this be done? Obviously a simple straight line would not be much use here.
Secondly, I would like to use the min and max (3rd and 4th columns respectively) to draw a shaded region around the modeled values in order to show the associated error.
I would eventually like to have something that looks like
http://www.giss.nasa.gov/research/briefs/rosenzweig_03/figure2.gif
Something like this?
%// Rename and sort your data
[x,I] = sort(dat(:,1));
y = dat(I,2);
mins = dat(I,3);
maxs = dat(I,4);
%// Assume a model of the form y = A + B/x. Solve for A and B
%// using least squares
P = [ones(size(x)) 1./x] \ y;
%// Initialize figure
figure(1), clf, hold on
set(1, 'Renderer', 'OpenGl');
%// Plot "shaded" areas
fill([x; flipud(x)], [mins; flipud(maxs)], 'y',...
'FaceAlpha', 0.2,...
'EdgeColor', 'r');
%// Plot data and fit
legendEntry(1) = plot(x, P(1) + P(2)./x, 'b',...
'LineWidth', 2);
legendEntry(2) = plot(dat(:,1), dat(:,2), 'r.',...
'Markersize', 15);

matlab: 2D line plot horizontal lines

This is actually very basic and I've done it before (a long tme ago) but I can't find it now; I have a vector of data points that I want to plot with a line plot; however I want the lines to be horizontal and jump between each point so that it basically looks like a histogram. I thought I could just use plot() with a certain linespec, but I can't find one that fits. Ideas?
I believe the function you are looking for is stairs:
x = linspace(-2*pi,2*pi,40);
stairs(x,sin(x))
Let x and y be two vectors of the same size to be plotted using plot(x,y). How about
yy = reshape( [y(:) y(:)]', 1, [] );
yy(end) = []; % discard last element
xx = reshape( [x(:) x(:)]', 1, [] );
xx(1) = []; % discard first element
plot( xx, yy );
title('does this do the trick for you?');

MATLAB axes have constant values

I am working on a project which plots deltaL on the y axis and Fnet on the x axis. The script is as follows:
%Variables for delta L
L=518;
E=1040000000;
A=0.0020268;
%Variables for Form Drag
Ad=25.437;
Cd=2.015;
p=999.835;
v=2.02917;
%Array for theta
theta=0:pi/360:pi/45;
Fd=0.5*p*Cd*v^2;
T=(L/2).*tan(theta);
Fnet=sqrt((T.^2)+(Fd.^2));
deltaL=(Fnet.*L)./(E.*A);
plot(Fnet,deltaL,'.');
When I plot the data, the values on the x axis are all the same and the values on the y axis are also the same. The x and y values are different. However, my graph still creates a working model of my data. Is there a piece of my code which is causing this issue or is there some glitch in matlab that can somehow be fixed?
That is because the precision of the values of x/y axis is not high enough.
You can use the trick from this page: http://www.mathworks.fr/support/solutions/en/data/1-3P8CU0/index.html?product=ML&solution=1-3P8CU0
old_ticks = get(gca, 'ytick')';
new_tick_labels = cellfun(#(x) sprintf('%9.6f',x), num2cell(old_ticks), 'uniformoutput', false);
set(gca, 'yticklabel', new_tick_labels)
old_ticks = get(gca, 'xtick')';
new_tick_labels = cellfun(#(x) sprintf('%9.6f',x), num2cell(old_ticks), 'uniformoutput', false);
set(gca, 'xticklabel', new_tick_labels)
result (right-click + "display image" for a better resolution):
You are trying to plot values that increase in very small magnitudes vs their initial value. For example if you would instead plot
plot(Fnet-Fnet(1),deltaL-deltaL(1),'.');
you'll see the relevant numbers that these change by.
A possible solution is to edit the xtick-labels and ytick-labels according to your needs. For Example
plot(Fnet,deltaL,'.');
yt=get(gca,'YTick')'
set(gca,'YTick',yt,'YTickLabel',num2str(yt,'%.6f'));
Actually, you can do it in a single line! just add:
set(gca,'YTick',get(gca,'YTick')','YTickLabel',num2str(get(gca,'YTick')','%.6f'));
Well, the values on the X and Y are not the same - it is just that Matlab rounds the numbers before displaying to 4 or 5 digits (Which is intended and meaningful behavior). You would need to choose a appropriate data presentation (e.g. use an offset for the X and Y data).
For example
xofs = round(mean(Fnet)*100)/100;
yofs = round(mean(deltaL)*10000)/10000;
plot( Fnet-xofs, deltaL-yofs );
xlabel( sprintf('Fnet - %0.2f', xofs) );
ylabel( sprintf('\\DeltaL - %0.4f', yofs) );