[X,Y] = meshgrid(-8:.5:8);
R = sqrt(X.^2 + Y.^2) + eps;
Z = sin(R)./R;
scatter3(X,Y,Z)
Error using scatter3 (line 64)
X, Y and Z must be vectors of the same length.
Matlab R2018b windows x64
As shown in the documentation, X, Y, Z must be vectors. (When you enter an article on mathworks from Googling, say, "matlab scatter3", you will first see the syntax for the function. Blue text means hyperlink. All the inputs are linked to the bottom of the page where their exact typing is defined.)
The reason is (probably) as follows.
As stated in the documentation, scatter3 puts circles (or other symbols of your choice if you modify the graphic object) on 3D coordinates of your choice. The coordinates are the ith element of X, Y, Z respectively. For example, the x-coordinate of the 10th point you wish to plot in 3D is X(10).
Thus it is not natural to input matrices into scatter3. If you know X(i), Y(i), Z(i) are indeed the coordinates you want to plot for all i, even though your X, Y, Z are not vectors for some reason, you need to reshape X, Y, Z.
In order to reshape, you can simply do scatter3(X(:), Y(:), Z(:)) which tells Matlab to read your arrays as a vectors. (You should look up in what order this is done. But it is in the intuitive way.) Or you can use reshape. Chances are: reshape is faster for large data set. But ofc (:) is more convenient.
The following should work:
[X,Y] = meshgrid(-8:.5:8);
R = sqrt(X.^2 + Y.^2) + eps;
Z = sin(R)./R;
X = X(:);
Y = Y(:);
Z = Z(:);
scatter3(X,Y,Z)
scatter3 needs vectors, not matrices as far as I can see here
this is my result:
If you want to use meshgrid without reshaping the matrices you have to use plot3 and the 'o' symbol. So you can get a similar result with:
plot3(X,Y,Z,'o')
EDIT:
A question that arose in association with this post was, which of the following methods is more efficient in terms of computation speed: The function reshape(X,[],1), suggested by me, or the simpler colon version X(:), suggested by #Argyll.
After timing the reshape function versus the : method, I have to admit that the latter is more efficient.
I added my results and the code I used to time both functions:
sizes = linspace(100,10000,100);
time_reshape = [];
time_col = [];
for i=1:length(sizes)
X = rand(sizes(i)); % Create random squared matrix
r = #() ResFcn(X);
c = #() ColFcn(X);
time_reshape = [time_reshape timeit(r)/1000] % Take average of 1000 measurements
time_col = [time_col timeit(c)/1000] % Take average of 1000 measurements
end
figure()
hold on
grid on
plot(sizes(2:end), time_col(2:end))
plot(sizes(2:end), time_reshape(2:end))
legend("Colon","Reshape","Location","northwest")
title("Comparison: Reshape vs. Colon Method")
xlabel("Length of squared matrix")
ylabel("Average execution time [s]")
hold off
function res = ResFcn(X)
for i = 1:1000 % Repeat 1000 times
res = reshape(X,[],1);
end
end
function res = ColFcn(X)
for i = 1:1000 % Repeat 1000 times
res = X(:);
end
end
Related
I have two grid coordinates matrices, X and Y, created by calling [X, Y] = meshgrid(x, y), so their elements represent coordinates. How can I plot a surface on the xy-plane, using heights from matrix V, only for coordinates that satisfy a specific equation? For example, my plot extends up to radius a, but I dont want to plot any data to the set of points that satisfy the equation sqrt(x^2 + (y-c)^2) < b, where b, c (a>b) are given constants and x=X(i,j), y=Y(i,j). Is there an easy way to do this, other than creating the two grid coordinates matrices (up to radius a) and then manually removing elements from X, Y, V, using nested for loops? I have not found any way to limit the plotting area I am interested in by changing x, y.
Using Logical Indexing
Just in case you're still looking for any implementation details. Referencing the comment by #Ander Biguri. I have to add that it might be easier to use mesh parameters X and Y directly in the logical indexing. Here is a little playground script that might help future readers. Below Region_Array is a logical array that specifies where the condition in this case sqrt(X.^2 + (Y-c).^2) < b is true. When true Region_Array is indexed with the value "1" and elsewhere with "0". I've split this into two steps just in case the complementary region is quickly wanted. The images/plots below show the resulting surf() and masks/regions. MATLAB has some thorough documentation and examples overviewing logical indexing: Find Array Elements That Meet a Condition
Trivial Surface Plot:
Masks/Regions Not to be Plotted:
Playground Script:
%Random test axes%
x = linspace(0,100,50);
y = linspace(0,100,50);
[X,Y] = meshgrid(x,y);
%Trivial plot of ones%
V = ones(length(x),length(y));
%Constant parameters%
b = 20;
c = 10;
%Eliminating within the curved region%
figure(1)
Region_Array = sqrt(X.^2 + (Y-c).^2) < b;
V(Region_Array) = NaN;
subplot(1,2,1); surf(X,Y,V);
axis([0 100 0 100]);
title("Eliminating Within the Curved Region");
%Eliminating outside the curved region%
V = ones(length(x),length(y));
V(~Region_Array) = NaN;
subplot(1,2,2); surf(X,Y,V);
axis([0 100 0 100]);
title("Eliminating Outside the Curved Region");
figure(2)
subplot(1,2,1); imshow(~Region_Array,'InitialMagnification',200);
title("Region Array Mask/Map (Inside)")
subplot(1,2,2); imshow(Region_Array,'InitialMagnification',200);
title("Region Array Mask/Map (Outside)")
Ran using MATLAB R2019b
I am trying to write a MATLAB function which interpolates data points in X to create a natural cubic spline, similar to interp1 but without using interp1. The function takes inputs vector x and c (from the system Ac=Y) and vector X of data points that I want to interpolate.
My function is almost complete, I have put the system in matrix form, found the y values, coefficients a,b,c and d but I do not know how to evaluate the X values to get my estimated value Y.
For example, this is what I have at the moment:
%cubic spline interpolation
n = length(x);
N = length(X);
Y = zeros(size(X));
for i = 1:n-1
for j = 1:N
while x(i) <= X(j) && x(i+1) >= X(j)
Y(j) = a(i)*(X(j)^3) + b(i)*(X(j)^2) + c(i)*X(j) + d(i);
break
end
end
end
My question is why does this not work? I know interp1 does not find the natural spline but I am very new to MATLAB so I was just using this built-in function as a reference as to how the graph should look and my function is just completely wrong. I hope that makes some sense. Any help would be great.
I have three vectors, one of X locations, another of Y locations and the third is a f(x, y). I want to find the algebraic expression interpolation polynomial (using matlab) since I will later on use the result in an optimization problem in AMPL. As far as I know, there are not any functions that return the interpolation polynomial.
I have tried https://la.mathworks.com/help/matlab/ref/griddedinterpolant.html, but this function only gives the interpolated values at certain points.
I have also tried https://la.mathworks.com/help/matlab/ref/triscatteredinterp.html as sugested in Functional form of 2D interpolation in Matlab, but the output isn't the coefficents of the polynomial. I cannot see it, it seems to be locked inside of a weird variable.
This is a small program that I have done to test what I am doing:
close all
clear
clc
[X,Y] = ndgrid(1:10,1:10);
V = X.^2 + 3*(Y).^2;
F = griddedInterpolant(X,Y,V,'cubic');
[Xq,Yq] = ndgrid(1:0.5:10,1:0.5:10);
Vq = F(Xq,Yq);
mesh(Xq,Yq,Vq)
figure
mesh(X, Y, V)
I want an output that instead of returning the value at grid points returns whatever it has used to calculate said values. I am aware that it can be done in mathematica with https://reference.wolfram.com/language/ref/InterpolatingPolynomial.html, so I find weird that matlab can't.
You can use fit if you have the curve fitting toolbox.
If it's not the case you can use a simple regression, if I take your example:
% The example data
[X,Y] = ndgrid(1:10,1:10);
V = X.^2 + 3*(Y).^2;
% The size of X
s = size(X(:),1);
% Let's suppose that you want to fit a polynome of degree 2.
% Create all the possible combination for a polynome of degree 2
% cst x y x^2 y^2 x*y
A = [ones(s,1), X(:), Y(:), X(:).^2, Y(:).^2, X(:).*Y(:)]
% Then using mldivide
p = A\V(:)
% We obtain:
p =
0 % cst
0 % x
0 % y
1 % x^2
3 % y^2
0 % x*y
I have a set of 3d data (300 points) that create a surface which looks like two cones or ellipsoids connected to each other. I want a way to find the equation of a best fit ellipsoid or cone to this dataset. The regression method is not important, the easier it is the better. I basically need a way, a code or a matlab function to calculate the constants of the elliptic equation for these data.
You can also try with fminsearch, but to avoid falling on local minima you will need a good starting point given the amount of coefficients (try to eliminate some of them).
Here is an example with a 2D ellipse:
% implicit equation
fxyc = #(x, y, c_) c_(1)*x.^2 + c_(2).*y.^2 + c_(3)*x.*y + c_(4)*x + c_(5).*y - 1; % free term locked to -1
% solution (ellipse)
c_ = [1, 2, 1, 0, 0]; % x^2, y^2, x*y, x, y (free term is locked to -1)
[X,Y] = meshgrid(-2:0.01:2);
figure(1);
fxy = #(x, y) fxyc(x, y, c_);
c = contour(X, Y, fxy(X, Y), [0, 0], 'b');
axis equal;
grid on;
xlabel('x');
ylabel('y');
title('solution');
% we sample the solution to have some data to fit
N = 100; % samples
sample = unique(2 + floor((length(c) - 2)*rand(1, N)));
x = c(1, sample).';
y = c(2, sample).';
x = x + 5e-2*rand(size(x)); % add some noise
y = y + 5e-2*rand(size(y));
fc = #(c_) fxyc(x, y, c_); % function in terms of the coefficients
e = #(c) fc(c).' * fc(c); % squared error function
% we start with a circle
c0 = [1, 1, 0, 0, 0];
copt = fminsearch(e, c0)
figure(2);
plot(x, y, 'rx');
hold on
fxy = #(x, y) fxyc(x, y, copt);
contour(X, Y, fxy(X, Y), [0, 0], 'b');
hold off;
axis equal;
grid on;
legend('data', 'fit');
xlabel('x'); %# Add an x label
ylabel('y');
title('fitted solution');
The matlab function fit can take arbitrary fit expressions. It takes a bit of figuring out the parameters but it can be done.
You would first create a fittype object that has a string representing your expected form. You'll need to work out the expression yourself that best fits what you're expecting, I'm going to take a cone expression from the Mathworld site for an example and rearrange it for z
ft = fittype('sqrt((x^2 + y^2)/c^2) + z_0', ...
'independent', {'x', 'y'}, 'coeff', {'c', 'z_0'});
If it's a simple form matlab can work out which are the variables and which the coefficients but with something more complex like this you'd want to give it a hand.
The 'fitoptions' object holds the configuration for the methods: depending on your dataset you might have to spend some time specifying upper and lower bounds, starting values etc.
fo = fitoptions('Upper', [one, for, each, of, your, coeffs, in, the, order, they, appear, in, the, string], ...
'Lower', [...], `StartPoint', [...]);
then get the output
[fitted, gof] = fit([xvals, yvals], zvals, ft, fo);
Caveat: I've done this plenty with 2D datasets and the docs state it works for three but I haven't done that myself so the above code might not work, check the docs to make sure you've got your syntax right.
It might be worth starting with a simple fit expression, something linear, so that you can get your code working. Then swap the expression out for the cone and play around until you get something that looks like what you're expecting.
After you've got your fit a good trick is that you can use the eval function on the string expression you used in your fit to evaluate the contents of the string as if it was a matlab expression. This means you need to have workspace variables with the same names as the variables and coefficients in your string expression.
I have two for loops like this:
for x = 1:1:15
for y = 1:1:15
values(x,y) = x^2 + y
end
end
This allows me to calculate x^2 + y for every combination of x and y if they are integers.
However, what if I want to calculate x^2 + y for decimals as well?
So something like this:
for x = 0:0.1:15
for y = 0:0.1:15
????? = x^2 + y
end
end
Could anyone help me find a method that can calculate all the possibilities of x^2 + y if x and y are decimals so cannot be used as index references anymore?
use meshgrid, matlab's built in rectangular grid in 2-D and there's no need to loop!
[y x]=meshgrid(0:0.1:15)
values=x.^2+y
to visualize this:
imagesc(values);
title('values=x^2+y'); axis square
xlabel('x'); ylabel('y'); colorbar;
axis xy;
set(gca,'XTick',1:10:151,'YTick',1:10:151);
set(gca,'XTickLabel',0:1:15,'YTickLabel',0:1:15);
EDIT:
mdgrid is also fine the only thing to note is that [y x]=meshgrid... is the same [x y]=ndgird...
Use:
[x y] = ndgrid(0:0.1:15);
values = x.^2 + y;
Issues with the other answers:
#inigo's answer will change the order of x and y compared to your initial example (by using meshgrid rather than ndgrid.
#NominSim's answer has to go to extra effort get d_x from x
#mecid's answer has to count columns and rows separately (also there is no ++ operator in MATLAB). If I was to go down #mecid's route I would use the following.
x = 0:.1:15;
y = 0:.1:15;
values = zeros(numel(x),numel(y));
for xnum = 1:numel(x)
for ynum = 1:numel(y)
values(xnum,ynum) = x(xnum)^2 + y(ynum);
end
end
Since it generated some discussion, from the documentation (within MATLAB, not in the online documentation) on the difference between meshgrid and ndgrid:
meshgrid is like ndgrid except that the order of the first two input and output arguments are switched (i.e., [X,Y,Z] = meshgrid(x,y,z) produces the same result as [Y,X,Z] = ndgrid(y,x,z)) ... meshgrid is also limited to 2D or 3D.
for x =1:0.1:15
for y=1:0.1:15
values(x*10-10, y*10-10) =x^2+y;
end
end
Why not loop on integers from 1 to 151 then calculate the decimal to be used? Then you can still use index references.
i.e.
for x = 1:1:151
for y = 1:1:151
d_x = x / 10.0 - 0.1
d_y = y / 10.0 - 0.1
values(x,y) = d_x^2 + d_y
end
end
(Forgive me if my syntax is slightly off, haven't used MATLAB in a while).