Histogram of multiple dataset with different dimension in Matlab - matlab

I can plot multiple plots with a same dimension in a histogram
x = rand(1000,3);
hist(x);
But I could not plot multiple plots with a different dimension.
x1 = rand(1100,1);
x2 = rand(1000,1);
x3 = rand(900,1);
x = [x1 x2 x3]
hist(x)
I get the following error
Error using horzcat
Dimensions of arrays being concatenated are not consistent.
Please someone point me to right direction to solve the problem.

Well the problem is indeed that you cant add non size matching vars.
Here is a patch work for you:
the magic is the Nan variable that make your code match
% its bad habits but:
x1 = rand(1100,1);
x2 = rand(1000,1);
x3 = rand(900,1);
% make em' all the same size
max_size = max([length(x1),length(x2),length(x3)]);
% add in the ending nan
x1 = [x1; nan(max_size-length(x1), 1)];
x2 = [x2; nan(max_size-length(x2), 1)];
x3 = [x3; nan(max_size-length(x3), 1)];
% plot em' bad
x = [x1 x2 x3];
figure;
hist(x)
Its working great now! (but you know its a bit of a Frankenstein masterpiece :-)

Triple Bar Histogram (3 datasets)
You can use the histogram() function and retrieve the .binCounts of each histogram and concatenate them in a fashion that gives a 10 by 3 array. By calling bar() on this 10 by 3 array you'll get a similar binning graph that shows the histogram of 3 datasets with the bins shown as triple bars. Also a good idea to use the histogram() function as the use of hist() is no longer recommended by MATLAB.
x1 = rand(1100,1);
x2 = rand(1000,1);
x3 = rand(900,1);
h1 = histogram(x1);
Counts_1 = h1.BinCounts;
h2 = histogram(x2);
Counts_2 = h2.BinCounts;
h3 = histogram(x3);
Counts_3 = h3.BinCounts;
Bin_Edges = h3.BinEdges;
Bin_Width = h3.BinWidth;
Bin_Centres = Bin_Edges(1:end-1) + Bin_Width/2;
Counts = [Counts_1.' Counts_2.' Counts_3.'];
bar(Counts);
title("Triple Bar Histogram");
xlabel("Bin Centres"); ylabel("Count");
set(gca,'xticklabel',Bin_Centres);
Ran using MATLAB R2019b

Related

How to remove coordinate specific entries from a matrix?

I'm having trouble to implement this (seemingly) simple task in Octave/Matlab.
I want to remove specific entries of a set of 2dimensional data. I have sample data (points of x and y coordinates) which contain specific areas that should not be further processed. I want to delete these areas from my sample data.
Here is an example for further understanding what I want to achieve. I would like to have:
B = A except the data in the red rectangle
Code Sample:
x = 0:pi/64:4*pi;
y = sin(x);
A = [x; y];
% Boundaries of the data that should be deleted
x1 = 4;
x2 = 6;
y1 = -1;
y2 = -0.5;
figure;
hold on;
plot(A(1,:),A(2,:),'bo');
plot([x1 x2 x2 x1 x1],[y1 y1 y2 y2 y1],'r-');
I know how to select the data within the red rectangle, which can be done with this command:
indices = find(A(1,:)>x1 & A(1,:)<x2 & A(2,:)>y1 & A(2,:)<y2);
B(1,:) = A(1,indices);
B(2,:) = A(2,indices);
plot(B(1,:),B(2,:),'g-x');
But I need the opposite: Select the data outside the red rectangle.
Any help is appreciated.
Invert all of the operators in your statement defining indices (i.e. > becomes < and vice-versa, AND[ & ] becomes OR[ | ]).
indices2 = find(A(1,:)<x1 | A(1,:)>x2 | A(2,:)<y1 | A(2,:)>y2);
B=A(:,indices2);
plot(B(1,:),B(2,:),'g-x');
Use logical arrays to select data
A very handy way of managing selections is the use of logical arrays. This is faster than using indices and allows the easy inversion of a selection as well as the combination of multiple selections. Here comes the modified selection function:
sel = A(1,:)>x1 & A(1,:)<x2 & A(2,:)>y1 & A(2,:)<y2
The result is a logical array that is a very memory efficient and fast representation of your information.
See figure for graphical representation of output.
Code Example
x = 0:pi/64:4*pi;
y = sin(x);
% Combine data: This is actually not necessary
% and makes the method more complicated. If you can stay with x and y
% arrays formulation becomes shorter
A = [x; y];
% Boundaries of the data that should be deleted
x1 = 4;
x2 = 6;
y1 = -1;
y2 = -0.5;
% Select interesting data
sel = A(1,:)>x1 & A(1,:)<x2 & A(2,:)>y1 & A(2,:)<y2;
% easily invert selection with the rest of data
invsel = ~sel;
% Get selected data to a new array
B1 = A(:,sel);
B2 = A(:,invsel);
% Display your data
figure;
hold on;
plot(B1(1,:),B1(2,:),'bo');
plot(B2(1,:),B2(2,:),'rx');
% Plot selection box in green
plot([x1 x2 x2 x1 x1],[y1 y1 y2 y2 y1],'g-');
Graphical Result
octave
matlab

Multivariate Normal Distribution Matlab, probability area

I have 2 arrays: one with x-coordinates, the other with y-coordinates.
Both are a normal distribution as a result of a Monte-Carlo simulation. I know how to find the sigma and mu for both array's, and get a 95% confidence interval:
[mu,sigma]=normfit(x_array);
hist(x_array);
x=norminv([0.025 0.975],mu,sigma)
However, both array's are correlated with each other. To plot the probability distribution of the combined array's, i use the multivariate normal distribution. In MATLAB this gives me:
[MuX,SigmaX]=normfit(x_array);
[MuY,SigmaY]=normfit(y_array);
mu = [MuX MuY];
Sigma=cov(x_array,y_array);
x1 = MuX-4*SigmaX:5:MuX+4*SigmaX; x2 = MuY-4*SigmaY:5:MuY+4*SigmaY;
[X1,X2] = meshgrid(x1,x2);
F = mvnpdf([X1(:) X2(:)],mu,Sigma);
F = reshape(F,length(x2),length(x1));
surf(x1,x2,F);
caxis([min(F(:))-.5*range(F(:)),max(F(:))]);
set(gca,'Ydir','reverse')
xlabel('x0-as'); ylabel('y0-as'); zlabel('Probability Density');
So far so good. Now I want to calculate the 95% probability area. I'am looking for a function as mndinv, just as norminv. However, such a function doesn't exist in MATLAB, which makes sense because there are endless possibilities... Does somebody have a tip about how to get a 95% probability area? Thanks in advance.
For the bivariate case you can add the ellispe whose area corresponds to NORMINV(95%). This ellipse is uniquely identified and for proof see the first source in the link.
% Suppose you know the distribution params, or you got them from normfit()
mu = [3, 7];
sigma = [1, 2.5
2.5 9];
% X/Y values for plotting grid
x = linspace(mu(1)-3*sqrt(sigma(1)), mu(1)+3*sqrt(sigma(1)),100);
y = linspace(mu(2)-3*sqrt(sigma(end)), mu(2)+3*sqrt(sigma(end)),100);
% Z values
[X1,X2] = meshgrid(x,y);
Z = mvnpdf([X1(:) X2(:)],mu,sigma);
Z = reshape(Z,length(y),length(x));
% Plot
h = pcolor(x,y,Z);
set(h,'LineStyle','none')
hold on
% Add level set
alpha = 0.05;
r = sqrt(-2*log(alpha));
rho = sigma(2)/sqrt(sigma(1)*sigma(end));
M = [sqrt(sigma(1)) rho*sqrt(sigma(end))
0 sqrt(sigma(end)-sigma(end)*rho^2)];
theta = 0:0.1:2*pi;
f = bsxfun(#plus, r*[cos(theta)', sin(theta)']*M, mu);
plot(f(:,1), f(:,2),'--r')
Sources
https://upload.wikimedia.org/wikipedia/commons/a/a2/Cumulative_function_n_dimensional_Gaussians_12.2013.pdf
https://en.wikipedia.org/wiki/Multivariate_normal_distribution
To get the numerical value of F where the top part lies, you should use top5=prctile(F(:),95) . This will return the value of F that limits the bottom 95% of data with the top 5%.
Then you can get just the top 5% with
Ftop=zeros(size(F));
Ftop=F>top5;
Ftop=Ftop.*F;
%// optional: Ftop(Ftop==0)=NaN;
surf(x1,x2,Ftop,'LineStyle','none');

Extract data from ezplot in MATLAB

I am trying to extract data from an ezplot, but when I plot the extracted data, I don't get the same graph (a and b are different)...
Could anybody elaborate on what's wrong?
Here is the code:
h = #(x,y)(x-((1/0.0175)*(y/5500)*(1+(y/5500)^9)))
a = ezplot(h,[0,700,0,7000]);
t = get(a,'xdata');
M = get(a,'ydata');
theta = transpose(t)
figure
b = plot(theta,M)
ezplot produces
whilst plot produces
This is what I get by extracting from the contour, there is still a straight line 3
ezplot returns a contour object. To extract the x and y data you need to use get(a,'contourMatrix'). Then the x data will be in the first column and the y data in the second column as
t = get(a,'contourMatrix');
x = t(1, :);
y = t(2, :);
Putting this altogether for your example we get
h = #(x,y)(x-((1/0.0175)*(y/5500)*(1+(y/5500)^9)))
a = ezplot(h,[0,700,0,7000]);
t = get(a,'contourMatrix');
x = t(1, :);
y = t(2, :);
figure;
b = plot(x, y);
xlabel('x');
ylabel('y');
title('({x}-(({1}/{0.0175}) ({y}/{5500}) ({1}+({y}/{5500})^{9}))) = {0}');
The resulting ezplot is
and the same from plot
You are getting the x and y axis values in calling get(a,'xdata') and get(a,'ydata'). That is the reason you're getting the straight line.
Try this instead:
h = #(x,y)(x-((1/0.0175)*(y/5500)*(1+(y/5500)^9)));
ezplot(h,[0,700,0,7000]);
a= get(gca,'Children');
l=get(a,'Children');
t = get(l,'xdata');
M = get(l,'ydata');
theta = transpose(t);
figure
b = plot(theta,M);
Sources:
Handle Graphics: Modifying Plots
How do I extract data from MATLAB figures?

Finding and plotting parabola in matlab

I have been trying to find a parabola in an image. For the starting purposes I took an image with a black parabola on a white background. Then I found the black pixels on the image using the find command by
[yi xi] = find(im<10); % im is the image with black parabola and white background
After that I randomly took 3 points from the collection and solved the equation for the parabola using the symbolic toolbox using
syms x y;
%solve them for the parabola equation
A = [ x^2 x y 1 ;x0^2 x0 y0 1; x1^2 x1 y1 1; x2^2 x2 y2 1];
where
%(x0,y0) = (104,137)
%(x1,y1) = (244,161)
%(x2,y2) = (300,229)
S = solve(det(A),y);
Then I get the coeffcients a,b,c as
a = 0.0100
b = -1.6800
c = 254.1900
where a, b and c are
a*x^2 + b*x + c = y;
Since now I have got the eqn I plot the parabola by putting the coefficient values
and taking
xx = 1:300;
yy = a*xx.^2 + b*xx +c ;
then I plot the parabola on the image as
plot(xx,yy,'-');
For the confirmation that I have taken correct points I also plot the selected points on the image and they lie exactly on the parabola in the image. So that is not the problem.
The problems are :
The parabola that I plot (blue) doesn't lie on the parabola of the image(black).
When I put the value of x co-ordinates in the above equation. The value of y is not the same as of the y co-ordinate.
for eg: (104,137)
0.0100*104*104 -1.68*104 + 254.19 = 108.16 - 174.72 + 254.19 = 187.63
whereas it should be 137
My parabola is wrong. Any help will be appreciated. The images are
I think you must be rounding somewhere in your calculation of a, b, and c.
I had a go with the three points you mentioned using the function fit (with fit type poly2) and my a,b,c were 0.0053, -1.6802 and 254.1895 (or add more decimal places when using format long).
Similarly, when using same the code you give, the output of solve is:
S = (73*x^2)/13720 - (5763*x)/3430 + 87187/343
S2 = double(coeffs(S))
S2 =
254.1895 -1.6802 0.0053
This gives me the same a, b, and c as with fit/poly2 (just from looking at it, the output of 73/13720 cannot be 0.01). Also, if I plot this curve over the original points using the same code you give, it works fine. So the only remaining source of error that I can see is some sort of rounding in whatever code you use to extract values of a, b, and c from the output of solve.
The following works. The habit of imshow to swap the intuitive meaning of ordinate and abscissa as used in plot can make overlays problematic at times. Your problem might stem from how you define your coordinate system when plotting with different function (imshow or related image display routines versus plot) in particular the position of the origin in the image. Here's my code:
% create image of parabola
k =[-0.3 10 10];
x = [1:0.1:50];
y = round(k(1)*x.^2 + k(2)*x + k(3));
crd = unique(round([x(:) y(:)]),'rows');
Nx = 100;
Ny = 100;
img = ones(Nx,Ny)*255;
iok = find((crd(:,1)>0) & (crd(:,1)<=Nx) & (crd(:,2)>0) & (crd(:,2)<=Ny));
indx = sub2ind([Nx Ny],crd(iok,1),crd(iok,2));
img(indx) = 0;
imshow(img)
Next we fit the parabola
% pick three points:
x0 = crd(1,1);
y0 = crd(1,2);
x1 = crd(80,1);
y1 = crd(80,2);
x2 = crd(160,1);
y2 = crd(160,2);
% plot these on the original image
hold on
plot(y0,x0,y1,x1,y2,x2,'Markersize',20,'Linestyle','none','Marker','x','Color','r')
Solved the equation precisely as you showed, then the result is
S = -1094/3627*x^2+12073/1209*x+37415/3627
Overlay the fitted equation
a= -1094/3627;
b = 12073/1209;
c = 37415/3627;
xx = 1:100;
yy = a*xx.^2 + b*xx +c ;
% then I plot the parabola on the image as
plot(yy,xx,'g--');
A not so pretty plot (green= fit, red crosses=picked points, blue=parabola plotted without swapping order of x and y):

Plotting histogram side by side in Matlab

I have two vectors, c and d, whose histogram I need to plot side by side in the same figure in matlab. when i do
hist(c);
hold on;
hist(d)
the scale changes and I cant see the histogram of c vector. Where am i going wrong? Any help will be appreciated.
If you want the two to be in the same figure, you could try adjusting the X and Y limits to suit your needs (try help xlim and help ylim). However plotting them in the same figure might not always suit your needs, as a particular plot has to of course maintain a certain limit for X and Y.
If displaying them side by side in different figures would suffice however, you could consider using subplot():
>> A=[1 1 1 2 2];
>> B=[1 2 2 2 2];
>> figure(1);
>> hold on;
>> subplot(1,2,1);
>> hist(A);
>> subplot(1,2,2);
>> hist(B);
Resultant figure:
Notice how the different axis limits are maintained.
You can use axis([xmin xmax ymin ymax]) to control the x and y axis and select a range that will display both histograms. Depending on what you want your plot to look like, you may also want to try using nelements = hist(___) to get the number of elements in each bin and then plot them using bar(x,nelements) to control the location of each bar.
hist assumes you want to divide the range into 10 equal sized bins by default. If you want to use the same bins for both histograms, first find the range of your values and make a set of bin centers (e.g. binCenters = linspace(min(x), max(x), 15)'), then callhist(x, binCenters)`.
I use MATLAB histograms quite frequently and have wrote this small matlab script to plot two histograms (first one red and second blue) in one figure. The script is quite simple but the important thing is that the histograms should be comparable (i.e. equally spaced frequency bins).
function myhist(varargin)
% myhist function to plot the histograms of x1 and x2 in a single figure.
% This function uses the same xvalue range and same bins to plot the
% histograms, which makes comparison possible.
if nargin<2
x1 = cell2mat(varargin(1));
x2 = x1;
res = 100;
elseif nargin==2
x1 = cell2mat(varargin(1));
if length(cell2mat(varargin(2)))==1
res = cell2mat(varargin(2));
x2 = x1;
else
x2 = cell2mat(varargin(2));
res = 100;
end
elseif nargin>2
x1 = cell2mat(varargin(1));
x2 = cell2mat(varargin(2));
res = cell2mat(varargin(3));
end
if numel(x1)~=length(x1) || numel(x2)~=length(x2)
error('Inputs must be vectors.')
return
end
xrangel = max(min(x1),min(x2));
xrangeh = min(max(x1),max(x2));
x1_tmp = x1(x1>=xrangel & x1<=xrangeh);
x2_tmp = x2(x2>=xrangel & x2<=xrangeh);
xbins = xrangel:(xrangeh - xrangel)/res:xrangeh;
hist(x1_tmp,xbins)
hold on
h = findobj(gca,'Type','patch');
set(h,'FaceColor','r','EdgeColor','w');
hist(x2_tmp,xbins)