drow cumulative distribution function in matlab - matlab

I have two vectors of the same size. The first one can have any different numbers with any order, the second one is decreasing (but can have the same elements) and consists of only positive integers. For example:
a = [7 8 13 6];
b = [5 2 2 1];
I would like to plot them in the following way: on the x axis I have points from a vector and on the y axis I have the sum of elements from vector b before this points divided by the sum(b). Therefore I will have points:
(7; 0.5) - 0.5 = 5/(5+2+2+1)
(8; 0.7) - 0.7 = (5+2)/(5+2+2+1)
(13; 0.9) ...
(6; 1) ...
I assume that this explanation might not help, so I included the image
Because this looks to me as a cumulative distribution function, I tried to find luck with cdfplot but with no success.
I have another option is to draw the image by plotting each line segment separately, but I hope that there is a better way of doing this.

I find the values on the x axis a little confusing. Leaving that aside for the moment, I think this does what you want:
b = [5 2 2 1];
stairs(cumsum(b)/sum(b));
set(gca,'Ylim',[0 1])
And if you really need those values on the x axis, simply rename the ticks of that axis:
a = [7 8 13 6];
set(gca,'xtick',1:length(b),'xticklabel',a)
Also grid on will add grid to the plot

Related

How do i correctly fit a line and force it through a particular point in an image?

I am to fit planes through various points in an image, but I am having issues with forcing the line through a particular point in the image. This happens particularly when the line is 90 degrees.
My code is as follows:
I = [3 3 3 3 3 2 2
3 3 3 3 2 2 2
3 3 3 3 2 2 2
3 3 1 2 2 2 2
1 1 1 2 2 2 2
1 1 1 1 1 2 2
1 1 1 1 1 1 1];
% force the line through point p
p = [3,3];
% points to fit plane through
edgeA = [3,3.5; 3,4; 2.5,4; 2,4; 1.5,4];
edgeB = [3.5,3; 4,3; 4.5,3; 5,3];
% fit a plane through p and edgeA
xws = [p(2), edgeA(:,2)']';
yws = [p(1), edgeA(:,1)']';
Cws = [xws ones(size(xws))];
dws = yws;
Aeqws = [p(2) 1];
beqws = [p(1)];
planefitA = lsqlin(Cws ,dws,[],[],Aeqws, beqws);
% fit a plane through p and edgeB
xwn = [p(2), edgeB(:,2)']';
ywn = [p(1), edgeB(:,1)']';
Cwn = [xwn ones(size(xwn))];
dwn = ywn;
Aeqwn = [p(2) 1];
beqwn = [p(1)];
planefitB = lsqlin(Cwn ,dwn,[],[],Aeqwn, beqwn);
%%%%% plot the fitted planes:
xAxis = linspace(0, size(I, 2), 12);
%obtain linear curve
fA = planefitA(1)*xAxis + planefitA(2);
fB = planefitB(1)*xAxis + planefitB(2);
%plot the fitted curve
RI = imref2d(size(I),[0 size(I, 2)],[0 size(I, 1)]);
figure, imshow(I, RI, [], 'InitialMagnification','fit')
grid on;
hold on;
plot(xAxis,fA, 'Color', 'b', 'linewidth', 2);
plot(xAxis,fB, 'Color', 'r', 'linewidth', 2);
All the points in edgeB fall on a 90 degrees line. However, the function ends up fitting a wrong line through those points. I know this because using
planefitB = polyfit([p(2), edgeB(:,2)'], [p(1), edgeB(:,1)'], 1);
works for this particular line but the problem is that i have these process repeated so many times at different locations in my image, hence i do not know how to suggest polyfit when the line would be 90 degrees.
Please, any ideas/suggestions on how i could make this work? Many thanks.
This amounts to the least squares solution of only the angle of the line. The offset is fixed by the fact that it has to go through (3,3). The easiest way to express this is by offsetting your data points by the known crossing. That is, subtract (3,3) from your data points, and fit the best m for y=mx, the b being fixed to 0.
For the non-vertical case, you can use a classic least-squares formulation, but don't augment the constant 1 into the Vandermonde matrix:
slope = (edgeA(:,2) - p(2)) \ (edgeA(:,1) - p(1));
This gives exactly the same answer as your constrained lsq solution.
Now for the vertical line: A non-vertical line can be expressed in the standard functional form of y=mx, where the least squares formulation implicitly assumes an independent and a dependent variable. A vertical line doesn't follow that, so the only general choice is a "Total Least Squares" formulation, where errors in both variables are considered, rather than just the residuals in the dependent (y) variable.
The simplest way to write this is to choose a and b to minimize ax - by, in the least squares sense. [x_k -y_k]*[a b].' should be as close to a zero vector as possible. This is the vector closest to the null space of the [x -y] matrix, which can be computed with the svd. Swapping columns and fudging signs lets us just use svd directly:
[u s v] = svd(bsxfun(#minus, edgeA, p));
The last column of v is the closest to the null space, so mapping back to your x/y definitions, (edgeA-p)*v(:,2) is the line, so the y multiplier is in the top position, and the x in the lower, with a sign flip. To convert to y=mx form, just divide:
slope = -v(2,2)/v(1,2);
Note that this answer will be quite a bit different than the normal least squares answer, since you are treating the residuals differently. Also, the final step of computing "slope" won't work in the vertical case for the reasons we've already discussed (it produces Inf), so you are probably better off leaving the line as a normalized 2-vector, which won't have any corner cases.

Count occurrences and stretch array in matlab

Let
input = [0 0 0 5 5 7 8 8];
I now want to transform this vector into the form
output = [3 3 3 3 5 5 6 8];
Which basically is a stairs plot.
Explanation
The input vector is used to plot data points along the x-axis. The y-axis is thereby provided by 1:length(input). So the resulting plot shows the cumulative number of datapoints along the y-axis and the time of occurrence along the x-axis.
I now want to fit a model against my dataset. Therefor I need a vector that provides the correct value for a certain time (x-value).
The desired output vector basically is the result of a stairs plot. I am looking for an efficient way to generate the desired vector in matlab. The result of
[x, y] = stairs(input, 1:length(input));
did not bring me any closer.
It can be done with bsfxun as follows:
x = [0 0 0 5 5 7 8 8];
y = sum(bsxfun(#le, x(:), min(x):max(x)), 1);
This counts, for each element in 1:numel(x), how many elements of x are less than or equal to that.

Smoothing out of rough plots

I want to draw some plots in Matlab.
Details: For class 1, p(x|c1) is uniform for x between [2, 4] with the parameters a = 1 and b = 4. For class 2, p(x|c2) is exponential with parameter lambda = 1. Besides p(c1) = p(c2) = 0.5 I would like to draw a sketch of the two class densities multiplied by P(c1) and P(c2) respectively, as
a function of x, clearly showing the optimal decision boundary (or boundaries).
I have the solution for this problem, this is what the writer did (and I want to get), but there's no Matlab code, so I want to do it all by myself.
And this is what I drew.
And this is the MATLAB code I wrote.
x=0:1:8;
pc1 = 0.5;
px_given_c1 = exppdf(x,1);
px_given_c2 = unifpdf(x,2,4);
figure;
plot(x,px_given_c1,'g','linewidth',3);
hold on;
plot(x,px_given_c2,'r','linewidth',3);
axis([0 8 0 0.5]);
legend('P(x|c_1)','P(x|c_2)');
figure;
plot(x,px_given_c1.*pc1,'g','linewidth',3);
hold on;
plot(x,px_given_c2.*(1-pc1),'r','linewidth',3);
axis([0 8 0 0.5]);
legend('P(x|c_1)P(c_1)','P(x|c_2)P(c_2)');
As you can see, they are almost smiliar, but I am having problem with this uniform distribution, which is drawn in red. How can I change it?
You should probably change x=0:1:8; to something like x=0:1e-3:8; or even x=linspace(0,8,1000); to have finer plotting. This increases number of points in vectors (and therefore line segments) Matlab will use to plot.
Explanation: Matlab works with line segments when it does plotting!
By writing x=0:1:8; you create vector [0 1 2 3 4 5 6 7 8] that is of length 9, and by applying exppdf and unifpdf respectively you create two vectors of the same length derived from original vector. So basically you get vectors [exppdf(0) exppdf(1) ... exppdf(8)] and [unifpdf(0) unifpdf(1) ... unifpdf(8)].
When you issue plot command afterwards Matlab plots only line segments (8 of them in this case because there are 9 points):
from (x(1), px_given_c1(1)) to (x(2), px_given_c1(2)),
...
from (x(8), px_given_c1(8)) to (x(9), px_given_c1(9)).

MATLAB: Four-part color logo(polygon)

My task is to write MATLAB code to produce a 4-part logo as shown in the screenshot. The top left should be black and the bottom right should be white. The other
two colours should be chosen randomly by the program.
I have taken the following approach:
clear all
clc
close all
x = [1 4 1 4 1 6.5 7 7];
y = [3 4 5.5 5 8 7 8 3];
fill(x,y,'k')
which creates the upper left black part. I wonder if that approach is good enough and if it is, what is the next step. I thought of storing those two variables in a shape object or something (I'm not familiar with Matlab) and rotate it somehow. Could you help me with that?
You don't need to rotate, just use the symmetry
clear all
clc
close all
x = [1 4 1 4 1 6.5 7 7];
y = [3 4 5.5 5 8 7 8 3]-3;
clrs=jet(10);
fill(x,y,'k')
hold on;
fill(2*max(x)-x,y,clrs(round(rand*10),:))
fill(x,-y,clrs(round(rand*10),:))
fill(2*max(x)-x,-y,'w')
The easiest way to do this all this, is to make sure that your center point (i.e. the point where the different colors meet), is positioned at [0,0]. Then a rotation of the figure (by multiple of 90°) boils down to changing the sign of either the x and/or y values of your contour.
If you need the figure to be at a point different from [0 0], just add these coordinates after you did the rotation.
So starting from your code, you can do this:
x = [1 4 1 4 1 6.5 7 7]-7;
y = [3 4 5.5 5 8 7 8 3]-3;
c = [5 6];
col = [0 0 0;
rand(2,3);
1 1 1];
fill( x+c(1), y+c(2),col(1,:)); hold on;
fill(-x+c(1), y+c(2),col(2,:));
fill( x+c(1),-y+c(2),col(3,:));
fill(-x+c(1),-y+c(2),col(4,:)); hold off;
edit: Clarification for the col and c variables.
The variable col contains the colors to be used in rgb style, where each row is a color. rand generates uniformly random numbers in the range [0,1], which is also where the values for the colors are expected to be. In the code above a 2x3 random matrix is generated, so that means 2 random colors which fits perfectly within the col matrix.
The variable c contains the center of your figure. If you look at the plot, the center will be at [5 6] (so 5 along the x axis and 6 along the y axis). You could use two variables instead, but I think that keeping both together in a variable is easier to deal with. I would personally do the same for your x and y variables, as that would allow you to use rotation matrices more easily, but that's just a matter of choice.

Generalize this matlab code for non-square matrices

I am working on some fourier transform code in matlab, and have come across the following:
xx = meshgrid(1:N);
% Center on DC
xx = xx - dcN;
% normalize dynamic range from -1 to 1
xx = xx./max(abs(xx(:)));
% form y coordinate from negative transpose of x coordinate (maintains symmetry about DC)
yy = -xx';
% compute the related radius of the x/y coordinates centered on DC
rr = sqrt(xx.^2 + yy.^2);
How can I generalize this for non-square matrices? This code is assuming my matrix is square, so dcN is the center of the square matrix (in other words, with 11x11, dcN = 6).
The math doesnt work out for that yy variable when the transpose is taken for a non-square matrix.
I have tried to figure out if I can make a meshgrid going from "top to bottom" instead of left to right - but I havent been able to figure taht out either.
Thanks
I have tried to figure out if I can
make a meshgrid going from "top to
bottom" instead of left to right - but
I havent been able to figure taht out
either.
>> N=5
N =
5
>> rot90(meshgrid(N:-1:1))
ans =
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
5 5 5 5 5
From your question I guess that you want to find rr, i.e. the distance of any element in the matrix from the center.
If you want this for a M-by-N array, you'd do the following
%# note that using meshgrid instead of ndgrid will swap xx and yy
[xx,yy] = ndgrid(-(M-1)/2:(M-1)/2,-(N-1)/2:(N-1)/2);
%# normalize to the max of xx,yy
nrm = max((M-1)/2,(N-1)/2);
xx = xx./nrm;
yy = yy./nrm;
rr = sqrt(xx.^2+yy.^2)