How do I plot my function to a mesh - matlab

I am a new MATLAB user and I am trying to plot a function:
function [ uncertainty ] = uncertain(s1, s2, p)
%UNCERTAIN calculates the measurement uncertainty of a triangulation
% provide two coordinates of known stations and a target coordinate
% of another point, then you get the uncertainty
[theta1, dist1] = cart2pol(p(1)-s1(1), p(2)-s1(2));
[theta2, dist2] = cart2pol(p(1)-s1(1), p(2)-s2(2));
theta=abs(pi-theta2-theta1);
uncertainty = dist1*dist2/abs(sin(theta));
end
called with:
uncertain([0 0],[8 0],[4 4])
I get a single result.
But i want a whole surface and called:
x=-2:.1:10;
y=-2:.1:10;
z = uncertain([0 0],[8 0],[x y]);
mesh(x,y,z)
I get the error: "Z must be a matrix, not a scalar or vector."
How can I modify my code so that my function draws a surface?
Thanks in advance.
Ralf.

First I think there's a mistake in your function: your [theta2, dist2] = cart2pol(p(1)-s1(1), p(2)-s2(2)); should have th first s1 being a s2.
Next, to get a vector answer out for your vector inputs, you have to change your p(i) (which selects the ith element of p) to p(i,:), which will select the first ith row of p.
After that, you change multiplication (*) to element-wise multiplication (.*).
In summary:
function [ uncertainty ] = uncertain(s1, s2, p)
%UNCERTAIN calculates the measurement uncertainty of a triangulation
% provide two coordinates of known stations and a target coordinate
% of another point, then you get the uncertainty
% target coordinates p are 2xn
% output uncertainty is 1xn
[theta1, dist1] = cart2pol(p(1,:)-s1(1), p(2,:)-s1(2));
[theta2, dist2] = cart2pol(p(1,:)-s2(1), p(2,:)-s2(2));
theta=abs(pi-theta2-theta1);
uncertainty = dist1.*dist2./abs(sin(theta));
end
The only changes are p(i) -> p(i,:), and *->.* and /->./.
To get a surface, you use meshgrid to get all sets of (x,y) coordinates in a grid, flatten them into a 2xn matrix for uncertain, and then expand them back out to the grid to plot. Example:
x=-2:.1:10; % 121 elements
y=-2:.1:10; % 121 elements
[xs,ys]=meshgrid(x,y); % xs and ys are each 121 x 121
zs = uncertain([0 0],[8 0],[xs(:) ys(:)]'); %get zs, being 1x(121*121) ie 1x14641
% Reshape zs to be 121x121 in order to plot with mesh
mesh(xs,ys,reshape(zs,size(xs)))
Note: you'll get lots of really big numbers because when theta is 0 or pi (or very nearly) because then you're dividing by (almost) 0.

Related

How to evaluate a vector valued function (or create vector field) on a MATLAB mesh?

I have a 3D grid set up as follows: [X,Y,Z] = ndgrid(0:2^(-8):1). I would like to evaluate and perform operations with vector fields defined at each point in a MATLAB meshgrid/ ndgrid. In other words, I want to assign three-dimensional vectors to every point in a mesh and perform pointwise operations with these vectors.
Implementations such as vec = [X.^2 ; 2*Y] end up concatenating matrices which makes it hard to perform operations such as dot and cross products.
Is there a way I can define a vector-valued function at each point in a mesh which takes as input, the coordinates of that point (the documentation only talked about evaluation scalar functions on meshes)? Or maybe there is a simpler implementation inbuilt in MATLAB?
Honestly, anything that would allow me to avoid subbing at 2^24 points would be appreciated.
Thanks!
Edit
My current implementation using symbolic substitution is as follows:
n=256;
[X,Y,Z] = ndgrid(0:1/n:1); % declaring 3D grid.
syms x y z; % declaring position variables.
xx = [x,y,z];
r1 = norm(xx-c1); % scalar field over grid.
n1 = (xx-c1)/r1; % vector field over grid.
v1 = cross(s1,n1); % vector field over grid.
w1 = n1'*v1; % tensor field over grid.
a = dot(v1,w1); % scalar field over grid.
% subbing in the value of scalar field 'a' (symbolic) into 3D array of doubles, A.
A = zeros(n+1,n+1,n+1);
for c = 1:n+1 % X
for d=1:n+1 % Y
for e= 1:n+1 % Z
A(c,d,e) = subs(a,[x,y,z],[X(c,0,0),Y(0,d,0),Z(0,0,e)]);
end
end
end
% use A in future computations.

Transform random draws from a bivariate normal into the unit square in Matlab

I have an nx2 matrix r in Matlab reporting n draws from a bivariate normal distribution
n=1000;
m1=0.3;
m2=-m1;
v1=0.2;
n=10000;
v2=2;
rho=0.5;
mu = [m1, m2];
sigma = [v1,rho*sqrt(v1)*sqrt(v2);rho*sqrt(v1)*sqrt(v2),v2];
r = mvnrnd(mu,sigma,n);
I want to normalise these draws to the unit square [0,1]^2
First option
rmax1=max(r(:,1));
rmin1=min(r(:,1));
rmax2=max(r(:,2));
rmin2=min(r(:,2));
rnew=zeros(n,2);
for i=1:n
rnew(i,1)=(r(i,1)-rmin1)/(rmax1-rmin1);
rnew(i,2)=(r(i,2)-rmin2)/(rmax2-rmin2);
end
Second option
rmin1, rmax1, rmin2, rmax2 may be quite variable due to the sampling process. An alternative is applying the 68–95–99.7 rule (here) and I am asking for some help on how to generalise it to a bivariate normal (in particular Step 1 below). Here's my idea
%Step 1: transform the draws in r into draws from a bivariate normal
%with variance-covariance matrix equal to the 2x2 identity matrix
%and mean equal to mu
%How?
%Let t be the transformed vector
%Step 2: apply the 68–95–99.7 rule to each column of t
tmax1=mu(1)+3*1;
tmin1=mu(1)-3*1;
tmax2=mu(2)+3*1;
tmin2=mu(2)-3*1;
tnew=zeros(n,2);
for i=1:n
tnew(i,1)=(t(i,1)-tmin1)/(tmax1-tmin1);
tnew(i,2)=(t(i,1)-tmin2)/(tmax2-tmin2);
end
%Step 3: discard potential values (very few) outside [0,1]
In your case the x and y coordinates of the random vector are correlated, so it's not just a transformation in x and in y independently. You first need to rotate your samples so that x and y become uncorrelated (then the covariance matrix will be diagonal. You don't need it to be the identity, since anywya you normalize later). Then you can apply the transformation you call "2nd option" to the new x and y independently. Shortly, you need to diagonalize the covariance matrix.
As a side note, your code adds/subtracts 3 times 1, instead of 3 times the standard deviation. Also, you can avoid the for loop, using (e.g) Matlab's bsxfun which applies an operation between matrix and vector:
t = bsxfun(#minus,r,mean(r,1)); % center the data
[v, d] = eig(sigma); % find the directions for projection
t = t * v; % the projected data is uncorrelated
sigma_new = sqrt(diag(d)); % that's the std in the new coordinates
% now transform each coordinate independently
tmax1 = 3*sigma_new(1);
tmin1 = -3*sigma_new(1);
tmax2 = 3*sigma_new(2);
tmin2 = -3*sigma_new(2);
tnew = bsxfun(#minus, t, [tmin1, tmin2]);
tnew = bsxfun(#rdivide, tnew, [tmax1-tmin1, tmax2-tmin2]);
You still need to discard the few samples which are out of [0,1], as you wrote.

What does the vector input in MATLAB fnplt do?

The documentation of fnplt says
A vector of the form [a,b], to indicate the interval over which to
plot the univariate function in f.
So I thought vector [a, b] means plotting the part of spline curve s that falls into the interval [a, b]. But the following experiments don't seem to support my this interpretation.
Running
x = [0.16;0.15;0.25;0.48;0.67];
y = [0.77;0.55;0.39;0.22;0.21];
spcv = cscvn([x, y].');
fnplt(spcv); % plot the full curve
hold on;
fnplt(spcv,[0.3,0.4],'r'); % plot the "[0.3, 0.4] part" in RED
fnplt(spcv,[1,2],'g'); % plot the "[1, 2] part" in GREEN
gives me this
How do I make sense of the results?
The spline, although constructed from known x and y points, is no longer a function of x and y. Instead, it is a function of the arc length along the spline. So the vector that you provide as the second input to fnplt is the range of that parameter and not x and y.
If you want to determine the correct ranges to pass to fnplt such that each piece of the spline (between successive input points) is a different color, you can use the output of cscvn to determine the values of the parameter at each input point.
spcv = cscvn([x, y].');
% form: 'pp'
% breaks: [0 0.4693 0.9037 1.4385 1.8746] <---- These are the parameter values
% coefs: [8x4 double]
% pieces: 4
% order: 4
% dim: 2
Specifically, we can use the breaks field to determine the parameter value corresponding to each input point and we can loop through these values to plot each section independently with fnplt.
colors = 'rgbc'
for k = 1:(numel(x) - 1)
fnplt(spcv, spcv.breaks([k k+1]), colors(k));
hold on
end

drawing 3d contour plot from 3d vector

I want to draw a contour plot for 3D data.
I have a force in x,y,z directions I want to plot the contour3 for that
the dimensions of the Fx = 21x21X21 same for Fy and Fz
I am finding force = f*vector(x,y,z)
Then
Fx(x,y,z) = force(1)
Fy(x,y,z) = force(2)
Fz(x,y,z) = force(3)
I did the following but it is not working with me ?? why and how can I plot that
FS = sqrt(Fx.^2 + Fy.^2 + Fz.^2);
x = -10:1:10;
[X,Y] = meshgrid(x);
for i=1:length(FS)
for j = 1:length(FS)
for k=1:length(FS)
contour3(X,Y,FS(i,j,k),10)
hold on
end
end
end
This is the error I am getting
Error using contour3 (line 129)
When Z is a vector, X and Y must also be vectors.
Your problem is that FS is not the same shape as X and Y.
Lets illustrate with a simple example:
X=[1 1 1
2 2 2
3 3 3];
Y=[1 2 3
1 2 3
1 2 3];
Z=[ 2 4 5 1 2 5 5 1 2];
Your data is probably something like this. How does Matlab knows which Z entry corresponds to which X,Y position? He doesnt, and thats why he tells you When Z is a vector, X and Y must also be vectors.
You could solve this by doing reshape(FS,size(X,1),size(X,2)) and will probably work in your case, but you need to be careful. In your example, X and Y don't seem programatically related to FS in any way. To have a meaningful contour plot, you need to make sure that FS(ii,jj,k)[ 1 ] corresponds to X(ii,jj), else your contour plot would not make sense.
Generally you'd want to plot the result of FS against the variables your are using to compute it, such as ii, jj or k, however, I dont know how these look like so I will stop my explanation here.
[ 1 ]: DO NOT CALL VARIABLES i and j IN MATLAB!
I'm not sure if this solution is what you want.
Your problem is that contour and contour3 are plots to represent scalar field in 2D objects. Note that ball is 2D object - every single point is defined by angles theta and phi - even it is an object in "space" not in "plane".
For representation of vector fields there is quiver, quiver3, streamslice and streamline functions.
If you want to use contour plot, you have to transform your data from vector field to scalar field. So your data in form F = f(x,y,z) must be transformed to form of H = f(x,y). In that case H is MxN matrix, x and y are Mx1 and Nx1 vectors, respectively. Then contour3(x,y,H) will work resulting in so-called 3D graph.
If you rely on vector field You have to specify 6 vectors/matrices of the same size of corresponding x, y, z coordinates and Fx, Fy, Fz vector values.
In that case quiver3(x,y,z,Fx,Fy,Fz) will work resulting in 6D graph. Use it wisely!
As I comment the Ander's answer, you can use colourspace to get more dimensions, so You can create 5D or, theoretically, 6D, because you have x, y, z coordinates for position and R, G, B coordinates for the values. I'd recommend using static (x,y,R,G,B) for 5D graph and animated (x,y,t,R,G,B) for 6D. Use it wisely!
In the example I show all approaches mentioned above. i chose gravity field and calculate the plane 0.25 units below the centre of gravity.
Assume a force field defined in polar coordinates as F=-r/r^3; F=1/r^2.
Here both x and yare in range of -1;1 and same size N.
F is the MxMx3 matrix where F(ii,jj) is force vector corresponding to x(ii) and y(jj).
Matrix H(ii,jj) is the norm of F(ii,jj) and X, Y and Z are matrices of coordinates.
Last command ensures that F values are in (-1;1) range. The F./2+0.5 moves values of F so they fit into RGB range. The colour meaning will be:
black for (-1,-1,-1),
red for (1,-1,-1),
grey for (0,0,0)
Un-comment the type of plot You want to see. For quiver use resolution of 0.1, for other cases use 0.01.
clear all,close all
% Definition of coordinates
resolution=0.1;
x=-1:resolution:1;
y=x;
z=-.25;
%definition of matrices
F=zeros([max(size(x))*[1 1],3]); % matrix of the force
X=zeros(max(size(x))*[1 1]); % X coordinates for quiver3
Y=X; % Y coordinates for quiver3
Z=X+z; % Z coordinates for quiver3
% Force F in polar coordinates
% F=-1/r^2
% spherical -> cartesian transformation
for ii=1:max(size(x))
for jj=1:max(size(y))
% temporary variables for transformations
xyz=sqrt(x(ii)^2+y(jj)^2+z^2);
xy= sqrt(x(ii)^2+y(jj)^2);
sinarc=sin(acos(z/xyz));
%filling the quiver3 matrices
X(ii,jj)=x(ii);
Y(ii,jj)=y(jj);
F(ii,jj,3)=-z/xyz^2;
if xy~=0 % 0/0 error for x=y=0
F(ii,jj,2)=-y(jj)/xyz/xy*sinarc;
F(ii,jj,1)=-x(ii)/xyz/xy*sinarc;
end
H(ii,jj)=sqrt(F(ii,jj,1)^2+F(ii,jj,2)^2+F(ii,jj,3)^2);
end
end
F=F./max(max(max(F)));
% quiver3(X,Y,Z,F(:,:,1),F(:,:,2),F(:,:,3));
% image(x,y,F./2+0.5),set(gca,'ydir','normal');
% surf(x,y,Z,F./2+.5,'linestyle','none')
% surf(x,y,H,'linestyle','none')
surfc(x,y,H,'linestyle','none')
% contour3(x,y,H,15)

How to find N values of 3D matrix that satisfy condition

I have a 3D array that is denoted by features. Each element of feature is a number x. Now I will get that number and calculate g(x) and f(x) of the number (g and f are functions of x). My problem is how to get N maximization of absolute value between g(x) and f(x). The function will return an array with N elements x. But I don't know how to get them. Could you help me?
This is my code:
%features is 3D array
%N is elements that we need
%Fs,sigmas,thetas are size of the array
% return N elements of features that maximization abs(f_s-g_s)
function features_filter=gabor_sort(features,N,Fs,sigmas,thetas)
for k = 1:numel(sigmas)
for j = 1:numel(Fs)
for i = 1:numel(thetas)
x= features(:,:,k,j,i);
f_x=x.^2;
g_x=x.^3+1;
s1=abs(f_x-g_x);
%%Do something in here to get maximization of s1
end
end
end
end
This isn't a problem. Create two matrices that will store the features we get for each combination of sigma, Fs and theta, as well as place your absolute values for each feature in this matrix, and when you're done, sort these distances in descending order. We can then use the second parameter of sort to give us the location of the features that maximize this distance. In other words, do this:
%features is 3D array
%N is elements that we need
%Fs,sigmas,thetas are size of the array
% return N elements of features that maximization abs(f_x-g_x)
function features_filter=gabor_sort(features,N,Fs,sigmas,thetas)
s1 = []; % s1 array to store our distances
xFeatures = []; %// Features to return
for k = 1:numel(sigmas)
for j = 1:numel(Fs)
for i = 1:numel(thetas)
x = features(:,:,k,j,i);
xFeatures = cat(3,xFeatures,x); %// Stack features in a 3D matrix
x = x(:); %// Convert to 1D as per your comments
f_x=mean(x.^2); %// Per your comment
g_x=mean(x.^3+1); %// Per your comment
s1 = [s1 abs(f_x-g_x)]; %// Add to s1 array
end
end
end
[~,sortInd] = sort(s1, 'descend');
%// Return a 3D matrix where each slice is a feature matrix
%// The first slice is the one that maximized abs(f_x - g_x) the most
%// The second slice is the one that maximized abs(f_x - g_x) the second most, etc.
features_filter = xFeatures(:,:,sortInd(1:N));
Minor note: This code is untested. I don't have access to your data, so I can't really reproduce. Hope this works!