I have a matrix of data. I used the polarplot command in MATLAB to plot this matrix with respect to theta.
The data oscillates between 3999.20 and 4001.52 As you can see in the following plot, the order of magnitude of oscillation of data is too small to see.
How can I modify my polar plot to see small oscillations?
My code is as below:
yf=[%750 data point]
theta = 0:4*pi/749:4*pi;
rho = yf
pax = polaraxes;
polarplot(theta,rho)
pax.ThetaDir = 'counterclockwise';
pax.ThetaZeroLocation='right'
pax.ThetaColor='r'
pax.ThetaTick=[0 30 60 90 120 150 180 210 240 270 300 330 ];
pax.RDir='normal';
pax.RTick=[3999.34 3999.67 4000 4000.33 4000.66 4000.99 4001.33 ]
pax.FontSize = 12;
Desired output:
Actual output
2-axis plot
To give an example of setting the r limits as suggested by #beaker
The following code uses the same data with using rlim to set manual limits in the second example. This scales the polar axis so that it only plots values between [3999,4000], exaggerating the scale of the oscillation.
theta = 0:0.01:2*pi;
rho = sin(2*theta).*cos(2*theta) + 3999 %To approximate your data
figure;
subplot(1,2,1)
polarplot(theta,rho)
title('Automatic r-limits')
subplot(1,2,2)
polarplot(theta,rho)
rlim([3999, 4000])
title('rlim([3999, 4000])')
Something like that maybe, where you subtract the mean of the data and scale the amplitude by a factor of 10?
yf=[%750 data point]
amp = yf - mean(yf);
amp = amp*10; % choose whatever scaling factor works for you
theta = 0:4*pi/749:4*pi;
rho = mean(yf) + amp;
Without the actual data, it's difficult to say what this will look like, but the general principle should work.
I have the following polygon which is just a set of 2D points as follows:-
poly0=[80 60
90 60
100 60
110 60
110 50
120 50
130 50
140 50
150 50
160 50
170 50
180 50
190 50
200 50
210 50
210 60
210 70
210 80
210 90
220 90
220 100
210 100
210 110
200 110
200 120
190 120
180 120
180 130
170 130
160 130
150 130
140 130
130 130
130 120
120 120
110 120
110 110
100 110
100 100
90 100
90 90
90 80
90 70
80 70
80 60];
Now I can plot it using.
>> line(poly0(:,1), poly0(:,2),'Color','k','LineWidth',3,'LineStyle',':');
This clearly shows one thing that my original set of polygon points is highly redundant. Basically, multiple points lying on the same straight line are enumerated above which is not needed. I could start checking each pair of points and if they are on the same straight line I could remove them. But that would mean using many for loops. I cannot come up with a smart vectorized way.
How do I get a new set of points which is much shorter in size than the previous but which still represents the exact same polygon? I should only have as many points as there are vertices in the polygon. So in other words how to find the vertices from the above data set in a quick way?
PS: Here the vertex angles are 90 degrees, but if you give a solution don't try to exploit that fact. I want a more general answer.
The two existing answers have large shortcomings:
Durkee's method only works if the distances between subsequent points is exactly identical. Points must have coordinates perfectly representable as floating-point values, so that the distances between subsequent points on a line can be found to be identical. If points are not equidistant, the method does nothing. Also, the start and end of the polygon are not examined together, so if a straight line is formed across the start/end of the polygon, one point too many will remain.
ShadowMan's method is better in that distances do not need to be identical, and the line across the start/end of the polygon is correctly handled. However it also uses floating point equality comparisons, which will not work in general. Only with integer coordinates will this method work correctly. Furthermore it uses vecnorm (which does a square root) and a division, both are relatively expensive operations (when compared to the method shown here).
To see if three points form a straight line, a simple arithmetic rule can be used. Let's say we have points p0, p1 and p2. The vector from p0 to p1 and the vector from p0 to p2 form the basis of a parallelogram, whose area can be computed by the cross product of the two vectors (in 2D, the cross product is understood to use z=0, with the resulting vector having x=0 and y=0, only the z value is useful; thus, the 2D cross product we assume to produce a scalar value). It can be computed as follows:
v1 = p1 - p0;
v2 = p2 - p0;
x = v1(1)*v2(2) - v1(2)*v2(1);
x, the cross product, will be zero if the two vectors are parallel, meaning that the three points are collinear. But the test for equality to 0 must have some tolerance, since floating-point arithmetic is inexact. I use 1e-6 as a tolerance here. Use a value that is several orders of magnitude smaller than the distance between your points.
Given an input set of points p, we can find the corner points with:
p1 = p; % point 1
p0 = circshift(p1,1); % point 0
v1 = p1 - p0; % vector from point 0 to 1
v2 = circshift(p1,-1) - p0; % vector from point 0 to 2
x = v1(:,1).*v2(:,2) - v1(:,2).*v2(:,1); % cross product
idx = abs(x) > 1e-6; % comparison with tolerance
p = p(idx,:); % corner points
Do note that this cross product test will fail if two consecutive points have identical coordinates (i.e. one of the vectors has a zero length). An additional test would be necessary if the data could have duplicated points.
Here are the results of the three methods. I've created a polygon with non-trivial coordinates and not equally spaced vertices. I've also put the start/end gap in the middle of a straight edge. These characteristics are purposeful to show the shortcomings of the other two methods.
This is the code I used to produce the graph:
% Make a polygon that will be difficult for the other two methods
p = [0,0 ; 0.5,0 ; 1,0 ; 1,1 ; 0.5,1 ; 0,1];
p = p + rand(size(p))/3;
p(end+1,:) = p(1,:);
q = [];
for ii = 1:size(p,1)-1
t = p(ii,:) + (p(ii+1,:) - p(ii,:)) .* [0;0.1;1/3;0.45;0.5897545;pi/4;exp(1)/3];
q = [q;t];
end
q = circshift(q,3,1);
figure
subplot(2,2,1)
plot(q(:,1),q(:,2),'bo-')
axis equal
title('input')
subplot(2,2,2)
res1 = method1(q);
plot(res1(:,1),res1(:,2),'ro-')
axis equal
title('Durkee''s method')
subplot(2,2,3)
res2 = method2(q);
plot(res2(:,1),res2(:,2),'ro-')
axis equal
title('ShadowMan''s method')
subplot(2,2,4)
res3 = method3(q);
plot(res3(:,1),res3(:,2),'go-')
axis equal
title('correct method')
% Durkee's method: https://stackoverflow.com/a/55603145/7328782
function P = method1(P)
a = logical([1 diff(P(:,1),2)' 1]);
b = logical([1 diff(P(:,2),2)' 1]);
idx = or(a,b);
P = P(idx,:);
end
% ShadowMan's method: https://stackoverflow.com/a/55603040/7328782
function corners = method2(poly0)
poly0Z = circshift(poly0,1);
poly0I = circshift(poly0,-1);
unitVectIn =(poly0 - poly0I)./vecnorm((poly0 - poly0I),2,2);
unitVectOut =(poly0Z - poly0)./vecnorm((poly0Z - poly0),2,2);
cornerIndices = sum(unitVectIn == unitVectOut,2)==0;
corners = poly0(cornerIndices,:);
end
% vecnorm is new to R2017b, I'm still running R2017a.
function p = vecnorm(p,n,d)
% n is always 2
p = sqrt(sum(p.^2,d));
end
function p = method3(p1)
p0 = circshift(p1,1);
v1 = p1 - p0;
v2 = circshift(p1,-1) - p0;
x = v1(:,1).*v2(:,2) - v1(:,2).*v2(:,1);
idx = abs(x) > 1e-6;
p = p1(idx,:);
end
Okay, I adapted this to deal with non-square corners.
Consider a triangle identified by the points
P = [0 0; 1 0; 2 0; 1.5 1; 1 2; .5 1; 0 0];
This is a 7x2 array, if we then define the 2 derivative vectors as defined by the question I mentioned in the comments.
a = logical([1 diff(P(:,1),2)' 1]);
b = logical([1 diff(P(:,2),2)' 1]);
From there, we may combine the two to get a new indexing variable
idx = or(a,b);
Finally, we may use this to make our plot
line(P(idx,1), P(idx,2),'Color','k','LineWidth',3,'LineStyle',':');
If you're doing a line plot, I think you need to set the last variable to false.
idx(end) = false;
The 'vector' way can be done quite elegantly. I tried a for loop way too and you can do the same thing that way but you asked for vector so here is my way of doing that.
The only change I made to your data was to remove any replicates prior to starting this script. Also, the points provided should be in sequential order going either clockwise or counter clockwise.
poly0Z = circshift(poly0,1);
poly0I = circshift(poly0,-1);
unitVectIn =(poly0 - poly0I)./vecnorm((poly0 - poly0I),2,2);
unitVectOut =(poly0Z - poly0)./vecnorm((poly0Z - poly0),2,2) ;
cornerIndices = sum(unitVectIn == unitVectOut,2)==0
corners = poly0(cornerIndices,:)
line(poly0(:,1), poly0(:,2),'Color','k','LineWidth',2,'LineStyle',':');
hold on
scatter(corners(:,1), corners(:,2),'filled')
The basis of this method is to go to each point, compute the unit vector coming in, and the unit vector going out. Points where the unit vector in does not match the unit vector out are corners.
[(Workspace)][1]I created random variables using covariance Matrix. I want to generate 300 random two dimensional feature data (length & weight) of each specie ω1 (salmon) and ω 2(bass).
Salmon (ω 1): mean: 65 cm, 22 kg covariance: [20 0.1; 0.1 70]
Sea bass (ω 2): mean : 80 cm, 31 kg covariance: [40 5; 5 50]
After I created Samples, I computed covariance Matrix again just to check out. But I found it totally wrong from the original covariance matrix. Can somebody help me out please? Attached is my code and different result. Please Help Me :(
I believe you might be creating the wrong data, try creating it this way:
% 0. INITILIZATION
clc, clear all, close all
rng default % For reproducibility
N = 200; %Number of samples
% 1. Data info
mu1 = [65 22]';
mu2 = [80 31]';
mu = [mu1 mu2];
covar1 = [20 0.1;0.1 70];
covar2 = [40 5;5 50];
% Data generation
Dset1 = mvnrnd(mu1,covar1,N)';
Dset2 = mvnrnd(mu2,covar2,N)';
figure('name', 'Data set X and X'''), hold on
% Plot the data
plot(Dset1(1,:),Dset1(2,:), 'b.',Dset2(1,:),Dset2(2,:), 'r.')
Also, if you want to check if the data has indeed the proper covariance, use a bigger N, say 5000 for example.
I would like to add a reference line on a 3d plot which follows the surface built with mesh(). I have 3 points in the x and y axis to build the line and so will need to interpolate to find z axis coordinates. Here is my code (with reproducible data) so far:
acceleration_dB = [0 109.3699 118.0084 133.9584 104.3017 110.5423 120.6332 140.6567 144.4194 129.7292]';
frequency = [1 50 50 50 100 100 100 100 100 500]';
voltage = [ 1.0e-04 * 0.0001 0.0968 0.1645 0.2983 0.0278 0.0368 0.0893 0.2785 0.4928 0.0780 ]';
xlin=linspace(0, max(frequency),33);
ylin=linspace(min(acceleration_dB), max(acceleration_dB),33);
[X, Y] = meshgrid(xlin,ylin);
f = scatteredInterpolant(frequency,acceleration_dB,log(voltage));
Z=f(X,Y);
figure();
mesh(X,Y,Z);
hold on
% Add threshold reference line
threshAccel = [97.0870 104.4212 109.5787]
threshFreq = [50 100 500]
Zthresh=f(threshFreq,threshAccel);
plot3(threshFreq,threshAccel,Zthresh,'Color','black','LineWidth',1)
Which gives:
What I would like is the black line following the plane of the surface for the whole length of the x-axis.
Any advice would be greatly appreciated. Thank you!
It is just a problem of range I think. This seems to work pretty well:
threshAccel = [97 97.0870 104.4212 109.5787]
threshFreq = [0 50 100 500]
but I am not sure about that 97 and 0 are the precise values. You should correct them probably.
The following methods are supposed to compute a PDF:
bins = [20 23 31.5 57 62.5 89 130]; % classes of values of my random variable
mean = 23;
std = mean/2;
values = mean + std*randn(1000,1); % the actual values of the RV
% method 1
[num, bins] = hist(values, bins); % histogram on the previously defined bins
pdf2 = num/trapz(bins, num);
trapz(bins, pdf2) % checking the integral under the curve, which is indeed 1
ans =
1
% method 2
pdf1 = normpdf(bins, mean, std); % the Matlab command for creating o normal PDF
trapz(bins, pdf1) % this is NOT equal to 1
ans =
0.7069
However if I consider the bins something like
bins = [0:46];
the results are
ans =
1
ans =
0.9544
so I still have not the value 1 for the integral in the case of normpdf.
Why does the normpdf not give the integral equal to 1 for the PDFs? Is there something I'm missing in the codes above?
The problem is that you are missing a lot of values from your PDF, if you take bins = [0:46], you have the following curve:
Which means you are missing all the part x < 0 and x > 46, so the integral you are computing is not from -oo to +oo as you expect but from 0 to 46, obvisouly you won't get the correct answer.
Note that you have mean = 23 and std = 11.5, thus if you have bins = 0:46 you have a band around the mean with a width of one std on each side, so according to the 68–95–99.7 rule, 95% of the values lie in this band, which is consistent with the 0.9544 you get.
If you take bins = -11.5:57.5, you now have three standard deviations on each side, and you will get 99.7% of the values in this band (MATLAB gives me 0.9973, the filled area are the ones you did not have with bins = 0:46):
Note that if you want to reach 1.000 with an error better than 10-3, you need about 3.4 standard deviations1:
>> bins = (mean - 3.4 * std):(mean + 3.4 * std) ;
>> pdf = normpdf(bins, mean, std) ;
>> trapz(bins, pdf)
0.9993
Note that with bins = [20 23 31.5 57 62.5 89 130];, you have both a problem of precision and a problem of missing values (your curve is the blue one, the red one was generated using bins = 20:130):
Obvisouly, if you compute the area under the blue curve, you won't get the value of the area under the red one, and you won't certainly get a value close to the integral of the red curve between -oo and +oo.