I have a set of data points (40 x 2), and I've derived the formula for the decision boundary which ends up like this :
wk*X + w0 = 0
wk is a 1 x 2 vector and X is a 2 x 1 point from the data point set; essentially X = (xi,yi), where i = 1,2,...,40. I have the values for wk and w0.
I'm trying to plot the line wk*X + w0 = 0 but I have no idea how to plot the actual line. In the past, I've done this by finding the minimum and maximum of the data points and just connecting them together but that's definitely not the right approach.
wk*X is simply the dot product between two vectors, and so the equation becomes:
w1*x + w2*y + w0 = 0
... assuming a general point (x,y). If we rearrange this equation and solve for y, we get:
y = -(w1/w2)*x - (w0/w2)
As such, this defines an equation of the line where the slope is -(w1/w2) with an intercept -(w0/w2). All you have to do is define a bunch of linearly spaced points within a certain range, take each point and substitute this into the above equation and get an output. You'd plot all of these output points in the figure as well as the actual points themselves. You make the space or resolution between points small enough so that we are visualizing a line when we connect all of the points together.
To determine the range or limits of this line, figure out what the smallest and largest x value is in your data, define a set of linearly spaced points between these and plot your line using the equation of the line we just talked about.
Something like this could work assuming that you have a matrix of points stored in X as you have mentioned, and w1 and w2 are defined in the vector wk and w0 is defined separately:
x = linspace(min(X(:,1)), max(X(:,1)));
y = -(wk(1)/wk(2))*x - (w0/wk(2));
plot(X(:,1), X(:,2), 'b.', x, y);
linspace determines a linearly spaced array of points from a beginning to an end, and by default 100 points are generated. We then create the output values of the line given these points and we plot the individual points in blue as well as the line itself on top of these points.
Related
Matlab functions meshgrid and streamline are not matching. How to fix?
%% direction field plot
[x,y]=meshgrid(-4:.5:4,-4:.5:4);
dx = 2*x +1*y;
dy = 1*x +2*y;
dxu = dx./sqrt(dx.^2+dy.^2);
dyu = dy./sqrt(dx.^2+dy.^2);
quiver(x,y,dxu,dyu)
hold on
%% Trajectory Plot
startx = repmat([-4:.5:4], 0,2);
starty = ones(size(startx));
streamline(x,y,dxu, dyu, startx, starty)
dxu = dx./sqrt(dx.^2+dy.^2);
dyu = dy./sqrt(dx.^2+dy.^2);
print('c:\data\DirectionField','-dmeta')
saveas(gcf, 'c:\data\streamline.emf')
hold off
Error messages are given below:
Error using repmat!
Replication factors must be a row vector of integers or integer scalars.
This has occurred when I added 7 trajectory plots to the code. When using only two trajectories the error did not occur? What is happening here?
MM
Your startx and starty matrices are currently empty. The last two arguments of repmat should be the number of times you want to repeat the matrix in the vertical and horizontal directions respectively. Since your replication factors are 0 and 2, the result is an empty matrix. Use positive integers for the replication factors.
I'm not completely sure what you're trying to do, but if you want the quiver and streamline plots to be consistent, I think you should not be using repmat at all. Instead, I think you should just do:
streamline(x, y, dxu, dyu, x, y);
Updated after OP's comment:
If you want to want to plot trajectories from a specific set of starting points, use the code below where startxy is an m x 2 matrix containing the coordinates of m starting points.
startxy = [0,2;
1,-3;
2,1]; %e.g. 3 starting points
streamline(x,y,dxu, dyu, startxy(:,1), startxy(:,2));
I have a robot leg (3 joints) and I've plotted the maximum range of the end of the leg in a 3D plot using convhull. Now, I want to be able to specify a particular height within that entire workspace and create a 2D plot with X and Y coordinates of all the possible points within the workspace at that height (3D plot works just as well but might be more difficult).
EDIT: Forgot to mention that the data is stored in a 3 by 1088 matrix with coordinates for each row. Also, since the Z coordinate might not match exactly the value I'm looking for, the next closest point works just as well.
Thank you.
If I am interpreting your question correctly, you wish to isolate out points in your matrix that match a particular z coordinate. Failing an exact match, you wish to find the closest z coordinate to your desired query. Also, since your data is stored in a 3 x 1088 matrix, you probably meant to say that each column is a coordinate, not each row.
I'm going to assume that the first, second and third rows denote the x, y and z coordinates of the movement of your robot. The first step would simply be to find the minimum distance between your desired z coordinate with all of those found in the matrix. Once you find that matching coordinate, we simply need to find those z coordinates in your matrix that match, isolate those out and plot only the x and y coordinates. Therefore, assuming your matrix of points is stored in data, and your query z coordinate is stored in queryZ, do something like this:
queryZ = 2.0; %// 1
zPoints = data(3,:); %// 2
[~,loc] = min(abs(queryZ - zPoints)); %// 3
minZ = zPoints(loc); %// 4
ind = data(3,:) == minZ; %// 5
xPoints = data(1,ind); %// 6
yPoints = data(2,ind); %// 7
plot(xPoints, yPoints, 'b.'); %// 8
title(['Points found for ' num2str(minZ)]); %// 9
The first line of code declares a desired z coordinate for you to search for. The next two lines extract out the z coordinates for your data, and then uses min and searches through the z coordinates and finds the location that is closest to your desired z coordinate. We use this location to extract out what the closest z coordinate is (line 4), then find those locations in your data matrix that share this same z coordinate (line 5).
Lastly, these locations are used to filter out the x and y coordinates of your data matrix (lines 6 and 7) and we then plot these points in blue and with dot markers (line 8). As a bonus, we place a title on the plot that shows you what the actual z coordinate was that matched to your query (line 9).
Edit
Given your inquiry in your comments, you would like to find multiple values of z within a particular tolerance for each value. The easiest way would be to do this in a for loop. There are certainly other ways to do this vectorized, but I won't invest the time into doing so. As such, you would have to slightly modify the above formulation and perform the following steps:
For each query point queryZ:
Find the closest point in your data
Search for all z points within a tolerance tol of this point
Add these points to a list
Repeat Step #1 for all query points desired
Plot all of these points for display
As such, the code would look something like this:
%// Step #1
queryZ = [2.0 1.0 -1.0 -2.0]; %// Define desired z points
tol = 0.001; %// Define tolerance here
zPoints = data(3,:); %// Extract out z points
%// Step #2
loc = false(numel(zPoints));
for idx = 1 : numel(queryZ)
z = queryZ(idx); %// Get query point
[~,minInd] = min(abs(z - zPoints)); %// Find closest point to query
minZ = zPoints(minInd);
loc(abs(minZ - zPoints) < tol) = true; %// Find indices within tolerance wrt closest point
%// Set to true
end
%// Step #3
xPoints = data(1,ind); %// 6
yPoints = data(2,ind); %// 7
plot(xPoints, yPoints, 'b.'); %// 8
The first step is self-explanatory. We first define a bunch of z coordinates that you are seeking, define a tolerance for similarity and extract out the z coordinates of your data. Next, for each point in our query set, we find the closest z coordinate to your data, and then with respect to this closest coordinate, we search for points that are within a specified tolerance of this matched point. We use these locations (not the coordinates) to mark into a logical array where true means that this point has met the criteria of being matched and false otherwise. In the end, any locations in the logical array that are set to true means that the corresponding point located at this index has met the criteria to be matched for at least one of the points in your query.
Finally, we use this logical array to index into our data, grab all of the valid points and plot them.
Hope this helps!
Can someone share a technique using MATLAB to plot the surface f(x,y)=(21/4)x^2y over the region x^2 <= y <= 1?
Also, if anyone is aware of some tutorials or links that would help with this type of problem, could you please share them?
Thanks.
Here is another approach:
%%
close all
x=linspace(-1,1,40);
g1=x.^2;
g2=ones(1,40);
y=[];
n=20;
for k=0:n
y=[y;g1+(g2-g1)*k/n];
end
x=x(ones(1,n+1),:);
z=21/4*x.^2.*y;
meshz(x,y,z)
axis tight
xlabel('x-axis')
ylabel('y-axis')
view(136,42)
And the result:
And finally, you can map the region (-1,1)x(0,1) in the uv-plane into the region bounded by $y=x^2 and y=1 in the xy-plane with the parametrization:
f(u,v) = (u\sqrt{v},v)
Capture from: https://math.stackexchange.com/questions/823168/transform-rectangular-region-to-region-bounded-by-y-1-and-y-x2
This code produces the same image shown above:
close all
[u,v]=meshgrid(linspace(-1,1,40),linspace(0,1,20));
x=u.*sqrt(v);
y=v;
z=21/4*x.^2.*y;
meshz(x,y,z)
axis tight
xlabel('x-axis')
ylabel('y-axis')
view(136,42)
First off, let's look at your valid region of values. This is telling us that y >= x^2 and also y <= 1. This means that your y values need to be on the positive plane bounded by the parabola x^2 and they also must be less than or equal to 1. In other words, your y values must be bound within the area dictated from y = x^2 to y = 1. Pictorially, your y values are bounded within this shape:
As such, your x values must also be bound between -1 and 1. Therefore, your actual boundaries are: -1 <= x <= 1 and 0 <= y <= 1. However, this only locates our boundaries for x and y but it doesn't handle where the plot has valid values. We'll tackle that later.
Now that we have that established, you can use ezsurf to plot surface plots in MATLAB that are dictated by a 2D equation.
You call ezsurf like so:
ezsurf(FUN, [XMIN,XMAX,YMIN,YMAX]);
FUN is a function or a string that contains the equation you want, and XMIN,XMAX,YMIN,YMAX contain the lowest and highest x and y values you want to plot. Plotting without these values assumes a span from -2*pi to 2*pi in both dimensions. As such, let's create a new function that will handle when we have valid values, and when we don't. Use this code, and save it to a new file called myfun.m. Make sure you save this to your current Working Directory.
function z = myfun(x,y)
z = (21/4)*x.^2.*y;
z(~(x.^2 <= y & y <= 1)) = nan;
end
This will allow you to take a series of x and y values and output values that are dictated by the 2D equation that you have given us. Any values that don't satisfy the condition of x^2 <= y <= 1, you set them to NaN. ezsurf will not plot NaN values.
Now, call ezsurf like so:
ezsurf(#myfun, [-1,1,0,1]);
You thus get:
This will spawn a new figure for you, and there are some tools at the top that will allow you interact with your 3D plot. For instance, you can use the rotation tool that's at the top bar beside the hand to rotate your figure around and see what this looks like. Click on this tool, then left click your mouse and hold the left mouse button anywhere within the surface plot. You can drag around, changing the azimuth and the latitude to get the perspective that you want.
Edit: June 4th, 2014
Noting your comments, we can decrease the jagged edges by increasing the number of points in the plot. As such, you can append a final parameter to ezsurf which is N, the number of points to add in each dimension. Increasing the number of points will decrease the width in between each point and so the plot will look smoother. The default value of N is 60 in both dimensions. Let's try increasing the amount of points in each dimension to 100.
ezsurf(#myfun, [-1,1,0,1], 100);
Your plot will look like:
Hope this helps!
Try the following to make the required function, compute the values, and plot only the region that is desired:
% Make the function. You could put this in a file by itself, if you wanted.
f = #(x,y) (21/4)*x.^2.*y;
[X Y] = meshgrid(linspace(0,1));
Z = f(X,Y);
% compute the values we want to plot:
valsToPlot = (X.^2 <= Y) & (Y <= 1);
% remove the values that we don't want to plot:
X(~valsToPlot) = nan;
Y(~valsToPlot) = nan;
Z(~valsToPlot) = nan;
% And... plot.
figure(59382);
clf;
surf(X,Y,Z);
I am charting the following data:
a=[...
0.1, 0.7, 0.00284643369242828;...
0.1, 0.71, 0.00284643369242828;...]
such that column 1 never surpasses approximately 10
also such that column 2 goes from .7 to 1.
Column 3 seems ok
When i chart my surface using surf(a) it looks like this:
it appears not to be properly considering what should be x and y.
anything seem weird there?
I think you need to try one of two things: either break out your height column into its own rectangular matrix Z and use surf(Z) to plot each point relative to its location in the matrix (so your x- and y-axes will not be scaled the way you want), or you can put your desired x- and y-coordinates in their own vectors, and plot the matrix Z (defined at every point (xi, yj) for all i in N and j in M where x is N elements long and y is M elements long) with surf(x,y,Z).
x = 0.1:0.1:10; % or whatever increment you need
y = 0.7:0.01:1; % or whatever increment you need
Z = zeros(length(x),length(y); % initialized to the correct size, fill with data
I think you are going to have to regenerate your Z-data so that it is in a rectangular matrix that is (elements in x) by (elements in y) in dimension.
EDIT: You do not need to recreate your data. If you know that you have n unique elements in x and m unique elements in y, then you can use:
X = reshape(data(:,1),m,n);
Y = reshape(data(:,2),m,n);
Z = reshape(data(:,3),m,n);
surf(X,Y,Z);
And that should give you what you are looking for.
I need to generate N random coordinates for a 2D plane. The distance between any two points are given (number of distance is N(N - 1) / 2). For example, say I need to generate 3 points i.e. A, B, C. I have the distance between pair of them i.e. distAB, distAC and distBC.
Is there any built-in function in MATLAB that can do this? Basically, I'm looking for something that is the reverse of pdist() function.
My initial idea was to choose a point (say A is the origin). Then, I can randomly find B and C being on two different circles with radii distAB and distAC. But then the distance between B and C might not satisfy distBC and I'm not sure how to proceed if this happens. And I think this approach will get very complicated if N is a large number.
Elaborating on Ansaris answer I produced the following. It assumes a valid distance matrix provided, calculates positions in 2D based on cmdscale, does a random rotation (random translation could be added also), and visualizes the results:
%Distance matrix
D = [0 2 3; ...
2 0 4; ...
3 4 0];
%Generate point coordinates based on distance matrix
Y = cmdscale(D);
[nPoints dim] = size(Y);
%Add random rotation
randTheta = 2*pi*rand(1);
Rot = [cos(randTheta) -sin(randTheta); sin(randTheta) cos(randTheta) ];
Y = Y*Rot;
%Visualization
figure(1);clf;
plot(Y(:,1),Y(:,2),'.','markersize',20)
hold on;t=0:.01:2*pi;
for r = 1 : nPoints - 1
for c = r+1 : nPoints
plot(Y(r,1)+D(r,c)*sin(t),Y(r,2)+D(r,c)*cos(t));
plot(Y(c,1)+D(r,c)*sin(t),Y(c,2)+D(r,c)*cos(t));
end
end
You want to use a technique called classical multidimensional scaling. It will work fine and losslessly if the distances you have correspond to distances between valid points in 2-D. Luckily there is a function in MATLAB that does exactly this: cmdscale. Once you run this function on your distance matrix, you can treat the first two columns in the first output argument as the points you need.