plot in matlab with similar xlabels spaces - matlab

I have a figure in matlab, where xlabel is 2 power n values, where n is an integer and ylable includes any vector values, I need to plot those values and keep x vector to be equal spaced. What I do now is correct but small spaces in xlabel are shown when x values are small while that becomes larger with higher values of x values.
That is what I did:
M = [2, 4, 8, 16, 32, 64, 128, 256];
s1 = [104 136 168 200 232 264 296 328];
figure(1)
semilogy(M, s1, 'ko-', 'LineWidth', 1); hold on; %
grid;
axis ([0 256 0 600])
xticks(M);

One way to have evenly spaced xticks is to use a linear vector (0,1,2,3,etc...) the same length as your data. You plot your y data versus this xa (X Apparent) vector, then just modify the xticklabels to display the proper power of 2 corresponding to each point.
So for your code:
max_xa = numel(M)-1 ; % number of "x" points (-1 because we'll start at 0)
xa = 0:max_xa ; % generate the x-apparent vector
figure
% Plot your "sl" values versus "xa"
semilogy(xa, s1, 'ko-', 'LineWidth', 1); grid on ;
axis ([0 max_xa 0 600]) % adust limits
xticklabels(M); % adjust X tick labels
will generate the following figure:
Note: We started the X apparent vector at 0 instead of 1 because otherwise Matlab would automatically insert a xtick at the value 0 and our xticklabels would all be offset by one position.

Your issues will remain unless you drop some xticklabels or better use loglog to plot which retains the feature of parabolic data.
Use following lines in your code:
loglog(M, s1, 'ko-', 'LineWidth', 1); hold on; %
You will get this result 1

Related

Matlab Scatter Plot (multiple y values)

I am trying to make a plot with multiple y-values for a single x-value. The code that I have been using plots this in two separate axes.
in = {[26 171 40], [34 32 104 28]}
titles = {'Locker','9u'}
for i = 1:length(in)
subplot(1,length(in), i);
scatter(ones(1,length(in{i})), in{i},'filled')
set(gca,'XTick',[])
xlabel(titles{i});
end
How can I plot my data in a single axes? I am not very experienced at using Matlab.
You can plot at different x locations, by multiplying the vector with ones by i. And then set the xticks, labels and axis limits appropriately.
As for the colors, you can make a length(in)-by-3 matrix containing the rgb values per category of data. Then provide the appropriate row of this matrix to scatter in the loop.
in = {[26 171 40], [34 32 104 28], randi(200, 5,1), randi(150, 3,1)};
titles = {'Locker','9u', 'A', 'B'};
category_colors = [
1, 0, 0; % color for 'Locker'
1, 0, 0; % '9u'
0, 0, 1; % 'A'
0, 0, 1; % 'B'
];
figure(1); clf;
hold on;
for i = 1:length(in)
scatter(ones(1,length(in{i}))*i, in{i},[], category_colors(i,:), 'filled'); % multiply ones with i
end
set(gca,'XTick',1:length(in));
set(gca, 'XTickLabel', titles);
xlim([0.5 length(in)+0.5])

Edit the x limits of least squares line

I created two scatter plots and then used lsline to add regression lines for each plot. I used this code:
for i=1:2
x = ..;
y = ..;
scatter(x, y, 50, 'MarkerFaceColor',myColours(i, :));
end
h_lines = lsline;
However, the darker line extends far beyond the last data point in that scatter plot (which is at around x=0.3):
lsline doesn't seem to have properties that allow its horizontal range to be set. Is there a workaround to set this separately for the two lines, in Matlab 2016a?
For a single data set
This is a workaround rather than a solution. lsline internally calls refline, which plots a line filling the axis as given by their current limits (xlim and ylim). So you can change those limits to the extent you want for the line, call lsline, and then restore the limits.
Example:
x = randn(1,100);
y = 2*x + randn(1,100); % random, correlated data
plot(x, y, '.') % scatter plot
xlim([-1.5 1.5]) % desired limit for line
lsline % plot line
xlim auto % restore axis limit
For several data sets
In this case you can apply the same procedure for each data set sequentially, but you need to keep only one data set visible when you call lsline; otherwise when you call it to create the second line it will also create a new version of the first (with the wrong range).
Example:
x = randn(1,100); y = 2*x + randn(1,100); % random, correlated data
h = plot(x, y, 'b.'); % scatter plot
axis([min(x) max(x) min(y) max(y)]) % desired limit for line
lsline % plot line
xlim auto % restore axis limit
hold on
x = 2*randn(1,100) - 5; y = 1.2*x + randn(1,100) + 6; % random, correlated data
plot(x, y, 'r.') % scatter plot
axis([min(x) max(x) min(y) max(y)]) % desired limit for line
set(h, 'HandleVisibility', 'off'); % hide previous plot
lsline % plot line
set(h, 'HandleVisibility', 'on'); % restore visibility
xlim auto % restore axis limit
Yet another solution: implement your own hsline. It's easy!
In MATLAB, doing a least squares fit of a straight line is trivial. Given column vectors x and y with N elements, b = [ones(N,1),x] \ y; are the parameters to the best fit line. [1,x1;1,x2]*b are the y locations of two points along the line with x-coordinates x1 and x2. Thus you can write (following Luis' example, and getting the exact same output):
N = 100;
x = randn(N,1); y = 2*x + randn(N,1); % random, correlated data
h = plot(x, y, 'b.'); % scatter plot
hold on
b = [ones(N,1),x] \ y;
x = [min(x);max(x)];
plot(x,[ones(2,1),x] * b, 'b-')
x = 2*randn(N,1) - 5; y = 1.2*x + randn(N,1) + 6; % random, correlated data
plot(x, y, 'r.') % scatter plot
b = [ones(N,1),x] \ y;
x = [min(x);max(x)];
plot(x,[ones(2,1),x] * b, 'r-')
You can get the points that define the line using
h_lines =lsline;
h_lines(ii).XData and h_lines(ii).YData will contain 2 points that define the lines for each ii=1,2 line. Use those to create en equation of a line, and plot the line in the range you want.

How to turn y axis of histogram to show percentage ranging from 0 to 1

I want to change the y axis of the histogram to show percentages ranging from 0 to 1. this is what I've tried, but it doesn't seem to be working.
myTolerance=1e-12; % in erg units.
nbins=50;
for j=1:ntM/100:ntM
H = histfit(Wkinet(abs(Wkinet(:,j))>myTolerance, j) * erg2eV, nbins);
%Select from column j all rows in column j whose absolute values are
%greater than the tolerance.
H(1).delete; %%Remove bins, only keep the fit.
set(gca, 'YScale', 'log');
set(gca, 'XScale', 'log'); % Make logarithmic X
yt = get(gca, 'YTick');
set(gca, 'YTick', yt, 'YTickLabel',
yt/numel(Wkinet(abs(Wkinet(:,j))>myTolerance)))
pause;
end
This is what is currently looks like:
This is what I want:
Just to simplify the discussion below, the line
H = histfit(Wkinet(abs(Wkinet(:,j))>myTolerance, j) * erg2eV, nbins);
is equivalent to
data = Wkinet(abs(Wkinet(:,j))>myTolerance, j) * erg2eV;
H = histfit(data, nbins);
This means below we'll assume data is a vector.
histfit computes and plots a histogram though histogram, then fits a function to it through fitdist. Since you don't want to plot the histogram itself, just stick to fitdist:
pd = fitdist(data,'Normal'); % this is the default distribution used in `histfit`, is it correct?
x = linspace(min(data),max(data),200); % 200 points in the graph, you might want to change this?
y = pdf(pd,x);
plot(x,y);
Now it's simple to normalize the plot however we want. For example set the first element to 1:
pd = fitdist(data,'Normal');
x = linspace(min(data),max(data),200);
y = pdf(pd,x);
y = y/y(1); % <<< Normalize
plot(x,y);
You can set limits on your y-axis using
ylim([1e-3 1]) %lower limit is nonzero since it's plotted on log scale
or
set(gca, 'ylim', [1e-3 1])

Matlab plot: remove connecting line between disconnected regions?

Assume you have 1000 indexed datapoints, with two labels grouped into region1 and region2. Here is an example of how to generate such random data
indices = 1:1000;
data = zeros(size(indices));
% some regions of data
region1 = [50:100 200:340 450:500 670:980];
region2 = setdiff(indices, region1);
% generating random data
data(region1) = rand(size(region1)) + 1;
data(region2) = rand(size(region2));
Now, if I plot these two regions I get a plot shown below
The code to generate the plot
% plotting
figure(1);
cla(gca);
hold on;
plot(region1, data(region1));
plot(region2, data(region2));
hold off;
Now the question: Is there an elegant way of removing the connecting lines between the disconnected data regions, without doing much data manipulation? I still want to use the solid line linestyle, or have a look similar to that.
If you make the x or y values into NaN then they wont be plotted. Since you have two complimentary regions, you can use them to set values to NaN...
% Two vectors which each cover ALL elements in "data", but with NaN where
% the other region is to be plotted. As per example, indices=1:1000;
r1 = 1:1000; r1(region2) = NaN;
r2 = 1:1000; r2(region1) = NaN;
% Plot all data for both lines, but NaNs wont show.
figure(1); clf;
hold on;
plot(r1, data);
plot(r2, data);
hold off;
Output:
Turns out if you represent regions as a vector of the same length as x and y with integer values representing the index of the region (e.g. regions = [1 1 1 2 2 1 1 1 ..]), there is an elegant one-linear that does the job for an arbitrary number of regions. Here is an example
% Generating test data
x = 1:1000;
y = sin(x/100) + rand(1, 1000);
regions = repelem([1 2 3 1 2 3 1 2 3 3], repelem(100, 10)); % a [1 x 1000] vector
% Plotting
plot(bsxfun(#rdivide, x(:), bsxfun(#eq, regions(:), unique(regions(:))')), y(:));
Here, I am building the matrix for x with values that should not be plotted being Inf, due to the #rdivide division by 0. The result is the following.
I hope this will be helpful for someone in the future.

Plot lines between points in a matrix in MATLAB

I have a matrix with n rows and 4 columns. The columns are x0, y0, and x1, y1 (so basically I have n pairs of point coordinates in 2D). I want to draw a line between corresponding point pairs (that is, only between x0, y0 and x1, y1 of one row).
Is it possible to do it without a loop? Because the following works but is very slow.
for i = 1:size(A.data, 1)
plot([A.data(i, 1), A.data(i, 3)], [A.data(i, 2), A.data(i, 4)], 'k-')
end
I came here looking for the same answer. I basically want a horizontal line for each x,y point, starting with that point's x-y value, and ending at the x value of the next xy pair, without a line joining that segment to that of the next xy pair. I can make the segments by adding new points between, with the old y and the new x, but I didn't know how to break up the line segments. But your wording (matrix) gave me an idea. What if you load your xy pairs to a pair of x, y vectors and - wait for it - separate your pairs with nan's in both the x and y vectors. I tried that with a very long sine wave, and it seems to work. A ton of disjoint line segments, that plot and zoom instantly. :) See if it solves your problem.
% LinePairsTest.m
% Test fast plot and zoom of a bunch of lines between disjoint pairs of points
% Solution: put pairs of x1,y1:x2,y2 into one x and one y vector, but with
% pairs separated by x and or y = nan. Nan is wonderful, because it leaves
% your vector intact, but it doesn't plot.
close all; clear all;
n = 10000; % lotsa points
n = floor(n/3); % make an even set of pairs
n = n * 3 - 1; % ends with a pair
x = 1:n; % we'll make a sine wave, interrupted to pairs of points.
% For other use, bring your pairs in to a pair of empty x and y vectors,
% padding between pairs with nan in x and y.
y = sin(x/3);
ix = find(0 == mod(x,3)); % index 3, 6, 9, etc. will get...
x(ix) = nan; % nan.
y(ix) = nan; % nan.
figure;
plot(x,y,'b'); % quick to plot, quick to zoom.
grid on;
This works for the data structure I have:
data = [
0, 0, 1, 0;...
1, 0, 1, 1;...
1, 1, 0, 1;...
0, 1, 0, 0 ...
];
figure(1);
hold off;
%slow way
for i = 1:size(data, 1)
plot([data(i, 1) data(i, 3)], [data(i, 2) data(i, 4)], 'r-');
hold on;
end
%fast way ("vectorized")
plot([data(:, 1)' data(:, 3)'], [data(:, 2)' data(:, 4)'], 'b-');
axis equal
This particular example draws a square.
The key is that MATLAB draws lines column-wise in the arguments. That is, if the arguments of plot have n columns, the line will have n-1 segments.
In a "connect-the-dots" scenario where all points in the vectors must be connected, this is irrelevant because MATLAB will transpose to get a column vector if it needs to. It becomes important in my application because I do not want to connect every point on the list - only pairs of points.
Try line for example
X=[1:10 ; 2*(1:10)];
Y=fliplr(X);
line(X,Y)