Find actual plot limits when specifying partially automatic limits - matlab

How do I find the actual y-range here:
This is just the example from the docs http://www.mathworks.com/help/matlab/ref/axis.html
x = linspace(-10,10,200);
y = sin(4*x)./exp(.1*x);
plot(x,y)
axis([-10 10 0 inf])
the ymin value is specified as zero and the max left automatic. If I now query the range with
get(gca,'YLim')
I just get [ 0 inf ]. How do i determine the actual plot y range used ( it is about [0 2.5] for this example..)
edit - aside
In case anyone else encounters this - it may be preferable to avoid the issue: make the plot with fully automatic ranging then fix the range as you like so you know exactly what it is, eg.
plot(x,y)
origYrange=ylim
origXrange=xlim
axis([origXrange 0 origYrange(2)])

Although the documentation doesn't tell, it appears that when the first (second) value of ylim is set to -inf (inf) Matlab sets the lower (upper) y-axis limit as the minimum (maximum) of all y values in the plot. The latter can be known by reading the 'YData' property of all 'children' of the axis.
yd = get(get(gca,'children'),'YData'); %// get y data of all plots
if iscell(yd) %// if there's more than one plot yd is a cell array of numeric vectors;
%// otherwise it's a numeric vector
yd = [yd{:}]; %// combine all values into a single numeric vector
end
ydminmax = [min(yd) max(yd)]; %// computed limits
result = ylim;
ind = isinf(result);
result(ind) = ydminmax(ind); %// replace infinite values by computed values
In your example, the result is
result =
0 2.4313

Related

How can I find a specific point in a figure in MATLAB?

I want a specific value in the figure in MATLAB. I put the black circle and arrow manually through the figure insert option. But How can I set the value now?
I want the x-axes values that are exactly 90% of each CDF curve.
here I am attaching my MatLab figure in jpg mode.
I would use interp1 to find the value. I'll assume that your x variable is called x and your cdf value is called c. You can then use code like this to get the x value where c = 0.9. This will work even if you don't have a cdf value at exactly 0.9
x_at_0p9 = interp1(c, x, 0.9);
You plotted those figures by using:
plot(X,Y)
So, your problem is to find x_0 value that makes Y = 0.9.
You can do this:
ii = (Y==0.9) % finding index
x_0 = X(ii) % using index to get x_0 value
Of course this will only work if your Y vector has exactly the 0.9 value.
As this is not always the case you may want to get the x_0 value that first makes Y to be greater or equal than 0.9.
Then you can do this:
ii = find(Y>=0.9, 1) % finding index
x_0 = X(ii) % using index to get x_0 value
Assuming that your values are x and Y (where x is a vector and the same for all curves) and Y is a matrix with the same number of rows and as many columns as there are curves; you just need to find the first point where Y exceeds 0.9:
x = (0:0.01:pi/2)'; % time vector
Y = sin(x*rand(1,3))*10; % value matrix
% where does the values exceed 90%?
lg = Y>= 0.9;
% allocate memory
XY = NaN(2,size(Y,2));
for i = 1:size(Y,2)
% find first entry of a column, which is 1 | this is an index
idx = find(lg(:,i),1);
XY(:,i) = [x(idx);Y(idx,i)];
end
plot(x,Y, XY(1,:),XY(2,:), 'o')

vectorising multiple calls of Matlab 'find'

I make a large number of calls to the 'find' function of Matlab. For example, the following should give the essence:
x=rand(1,10^8);
indx=zeros(1,10^8);
for i=1:10^8
indx(i) = find([0.2, 0.52, 0.76,1] < x(i), 1, 'last');
end
Is there a way to vectorize this code to speed it up? Just including x as a vector creates an error. If vectorization is not possible, then any other suggestions for speed would be appreciated. The actual problem I wish to solve has a considerably longer vector in the place of [0.2, 0.52, 0.76,1], so any solution shouldn't depend on the specific vector I provided.
thanks.
For MATLAB versions R2015a and newer, the answer from crjones gives the best option using discretize:
edges = [0.2, 0.52, 0.76, 1];
indx = discretize(x, edges, 'IncludedEdge', 'right');
Any values in x outside the range of edges will have NaN for their indices.
For MATLAB versions R2014b and newer you can also use histcounts:
[~, ~, indx] = histcounts(x, edges);
The differences with discretize are that you can also get the count of values in each bin (the first output), and indices for values in x outside the range of edges will be 0.
For MATLAB versions prior to R2014b you can use histc (deprecated in newer versions):
[~, indx] = histc(x, edges);
Again, you can also get the count of values in each bin (the first output), and indices for values in x outside the range of edges will be 0.
Based on your example, you may want to consider using the discretize function for this:
x=rand(1,10^8);
edges = [0.2, 0.52, 0.76, 1];
indx = discretize(x, edges, 'IncludedEdge', 'right');
Note that cases outside of the range will result in NaN.
% small test case
% x = [0.5198, 0.0768, 0.6788, 0.9496]
% indx = discretize(x, edges, 'IncludedEdge', 'right')
% answer: 1 NaN 2 3
Of course, this will only be applicable if you're trying to find where x fits in a well-ordered set.
Compare your vector with x to get a logical matrix indicating the values lesser in vec than x. Multiply that logical matrix with column vector representing the column subscripts. Use max to find the maximum (last) index that satisfies the inequality. For the case where inequality doesn't satisfy, you will get zero.
vec = [0.2, 0.52, 0.76, 1]; %Your vector
indx = bsxfun(#lt, vec(:), x); %Making 'vec' a column matrix and comparing with 'x'
indx = max(bsxfun(#times, indx, (1:numel(vec)).')); %The required result
With R2016b and later versions, you can use implicit expansion instead of bsxfun:
indx = vec(:) < x ;
indx = max(indx .* (1:numel(vec)).');

Finding the last X-axis value in MATLAB

I am interested in finding the final value of the x-axis for this graph.
[
I've tried using the Xlim command to obtain the range of values along the x-axis, but it gave me the range of the entire graph ([0 250000]) rather than the final value of the graph, located around ~22000 Hz. Is there a function in MATLAB that can find this value for me?
Assuming your x-values are in the variable 'x' just do:
max(x)
I'm assuming you want to obtain that value from the graph, that is, you don't have access to the variables that originated the graph.
Get the 'XData' and 'YData' of the plotted curve, and then look for the point with greatest x value:
ch = get(gca, 'Children'); %// all children of current axes
ch = findobj(ch, 'type', 'line'); %// keep only line objects
xData = get(ch(1), 'XData'); %// take first line object, if there are more than one
yData = get(ch(1), 'YData');
[resultX, ind] = max(xData); %// resultX is the greatest x value in the graph
resultY = yData(ind); %// resultY is the corresponding y value

Displaying Marker Values Within a MatLab Plot

I'm trying to display my values for a given vector within a plot. My code is:
x = [0.1 0.2 -0.1 4.1 -2 1.5 -0.1];
plot(x)
a = num2str(x(:));
b = cellstr(a);
c = strtrim(b);
text(x,y,c);
Its plotting the values, but they are scattered all over the place, and not sitting nicely next to each point on the graph.
As I said in my comment above, calling plot with a single vector input treats the values of the vector as the y-coordinates and their indices as the x-coordinates. Your provided x vector contains negative numbers, but your plot call only has one vector input, so there will be no negative x-coordinates in the plot (there are no negative indices in MATLAB).
Assuming your x vector is your desired y-coordinate, the following example will provide the behavior I'm guessing you're expecting:
y = [0.1 0.2 -0.1 4.1 -2 1.5 -0.1];
x = 1:1:length(y);
plot(x,y)
a = num2str(x(:));
b = cellstr(a);
c = strtrim(b);
h = text(x,y,c);
Where h is an array of object handles that you can use with get and set to query and modify the properties of each individual text object (like size, alignment, etc.).

matlab find line interception and represent it

For this given example:
a=rand(100,1)
ecdf(a)
The obtained plot will have on x proportion of bin values, and on y the proportion of points. I wanted to add a line y=0.5 (50% percent of values) and when cross the line in the plot gather and shows the predicted x value.
It is possible but it suppresses my knowledge.
Thanks in advance
Not sure I interpret your question correctly - but could it be as simple as
a=rand(100,1)
ecdf(a)
hold on
plot([0 1],[1 1]*0.5);
This adds a line at a height of 0.5 from 0 to 1 (which I believe are the limits of the plot that ecdf produced for you).
If you want to find the point where these two lines intersect, you need to obtain the points in the plot using a different form of the ecdf function:
a = rand(100,1)
[f x] = ecdf(a);
figure
plot(x, f); % now you have to make the plot yourself...
hold all
plot(x, 0.5 * ones(size(x))); % add the line at y=0.5
title 'cumulative probability of rand()'
xest = interp1(f, x, 0.5); % interpolate - find x where f would be 0.5
fprintf(1, 'The intercept is at x=%.2f\n", xest);