Smoothing out of rough plots - matlab

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)).

Related

How to plot a Diagonal Histogram in Matlab

Given scatter data, or a matrix, I would like to generate a nice plot such as the one shown below, with all 3 histograms and a colored matrix. I'm specifically interested in the diagonal histogram, which ideally, would correspond to the diagonals of a matrix:
Source figure: www.med.upenn.edu/mulab/jpst.html
The existing command scatterhist is not that powerful to generate this type of graph. Any ideas?
Thanks!
EDIT:
Following #Cris Luengo's hints, I came up with the following code which does some first work at the inclined histogram: WORK IN PROGRESS (HELP WELCOME)!!
b = [0 1 2 3 4 5 6 7 8 9 10];
h = [0.33477 0.40166 0.20134 0.053451 0.008112 0.000643 2.7e-05 0 0 0 0];
wid = 0.25; bb = sort([b-wid b-wid b+wid b+wid]);
kk = [zeros(numel(h),1) h(:) h(:) zeros(numel(h),1)];
kk = reshape(kk',[1,numel(kk)]);
pp=patch(bb,kk,'b');axis([-.5 5 0 .5])
set(gca,'CameraUpVector',[-1,.08,0]);axis square
EDIT 2: Using rotation
phi = pi/4;
R = [cos(phi),-sin(phi);sin(phi),cos(phi)];
rr = [bb' kk'] * R;
bb = rr(:,1); kk = rr(:,2);
patch(bb,kk,'b'); axis([-.5 3 -4 .5])
Here is a recipe to plot the diagonal histogram, if you can do that I’m sure you can figure out the rest too.
Compute the histogram, the bin counts are h, the bin centers are b.
Build a coordinate matrix, attaching the coordinates of a point on the x-axis at the left and right ends of the histogram:
coords = [b(:),h(:)];
coords = [coord;b(end),0;b(1),0];
Using patch you can now plot the histogram as follows:
patch(coords(1,:),coords(2,:));
To plot a rotated histogram you can simply multiply the coords matrix with a rotation matrix, before using patch:
phi = pi/4;
R = [cos(phi),-sin(phi);sin(phi),cos(phi)];
coords = R * coords;
You might need to shift the plot to place it at the right location w.r.t. the other elements.
I recommend that you place all these graphic elements in the same axes object; you can set the axes’ visibility to 'off' so that it works only as a canvas for the other elements.
It will be a bit of work to get everything placed as in the plot you show, but none of it is difficult. Use the low-level image, line,patch and text to place those types of elements, don’t try to use the higher-level plotting functions such as plot, they don’t provide any benefits over the low-level ones in this case.

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.

Matlab 3D Plot of transfer function magnitude

How can I plot amplitude of transfer function in three dimension (for instance to check poles and zeros on graph) ?
Suppose this is my transfer function:
My code:
b = [6 -10 2];
a = [1 -3 2];
[x, y] = meshgrid(-3:0.1:3);
z = x+y*j;
res = (polyval(b, z))./(polyval(a,z));
surf(x,y, abs(res));
Is it correct? I'd also like to know is it possible to mark unit circle on plot?
I think it's correct. However, you're computing H(z^-1), not H(z). Is that you want to do? For H(z), just reverse the entries in a from left to right (with fliplr), and do the same to b:
res = (polyval(fliplr(b), z))./(polyval(fliplr(a),z));
To plot the unit circle you can use rectangle. Seriously :-) It has a 'Curvature' property which can be set to generate a circle.
It's best if you use imagesc instead of surf to make the circle clearly visible. You will get a view from above, where color represents height (value of abs(H)):
imagesc(-3:0.1:3,-3:0.1:3, abs(res));
hold on
rectangle('curvature', [1 1], 'position', [-1 -1 2 2], 'edgecolor', 'w');
axis equal
I have never in my whole life heard of a 3D transfer function, it doesn't make sense. I think you are completely wrong: z does not represent a complex number, but the fact that your transfer function is a discrete one, rather than a continuous one (see the Z transform for more details).
The correct way to do this in MATLAB is to use the tf function, which requires the Control System Toolbox (note that I have assumed your discrete sample time to be 0.1s, adjust as required):
>> b = [6 -10 2];
a = [1 -3 2];
>> sys = tf(b,a,0.1,'variable','z^-1')
sys =
6 - 10 z^-1 + 2 z^-2
--------------------
1 - 3 z^-1 + 2 z^-2
Sample time: 0.1 seconds
Discrete-time transfer function.
To plot the transfer function, use the bode or bodeplot function:
bode(sys)
For the poles and zeros, simply use the pole and zero functions.

drow cumulative distribution function in 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

Removing the line between two specific data points in Matlab

I am going to draw a graph in Matlab. The graph is quite simple and I am using the plot function.
Suppose the data that I want to plot is (0:1:10). I also put markers on my graph. Then, we have a line that has markers on coordinates (0,0),(1,1),(2,2),... etc.
Now, I want to remove the line between (2,2) and (3,3) without deleting the whole line. That is to say, my purpose is to get rid of a particular segment of the line without loosing the entire line or any marker points.
How can I do that?
Removing the section of line after you have plotted it is difficult. You can see that the line is made up of one MATLAB object by the following code:
x = 1:10;
y = 1:10;
H = plot(x, y, '-o');
get(H, 'children')
ans =
Empty matrix: 0-by-1
We can see that the line has no children, so there are no 'subparts' that we can remove. However, there are some cheeky tricks we can use to try to achieve the same effect.
Plot two lines separately
...using hold on. See Victor Hugo's answer. This is the proper way of achieving our goal.
Plot two separate lines in one
MATLAB doesn'y plot points with a NaN value. By modifying the input vectors, you can make MATLAB skip a point to give the effect of a broken line:
x = [0 1 2 2 3 4 5 6 7 8 9];
y = [0 1 2 nan 3 4 5 6 7 8 9];
plot(x, y, '-o');
This is equivalent to plotting a line from [0, 0] to [2, 2], skipping the next point, then starting again at [3, 3] and continuing to [9, 9].
'Erase' part of the line
This is the nastiest way of doing it, but is a cheap hack that could work if you can't be bothered with changing your input arrays. First plot the line:
x = 1:10; y = 1:10;
plot(x, y, '-o');
Now plot a white line over the part you wish to erase:
hold on
plot([2 3], [2 3], 'w');
As you can see, the result doesn't quite look right, and will respond badly if you try to do other things to the graph. In short, I wouldn't recommend this method but it might come in useful in desperate times!
Try the following:
y = [0.2751 0.2494 0.1480 0.2419 0.2385 0.1295 0.2346 0.1661 0.1111];
x = 1:numel(y);
plot(x(1:4), y(1:4), '-x')
hold
plot(x(5:end), y(5:end), '-x')