Interpolation value from 3D matrices - matlab

With 3 vectors and 3 functions, I'm building 3 result matrices. Here's a short and simplified example of what I'm actually doing:
xVec = -0.2:0.05:0.2; % Vector 1
yVec = 0:0.1:0.4; % Vector 2
zVec = 1:3; % Vector 3
[X,Y,Z] = meshgrid(xVec,yVec,zVec);
R1 = (X.^2+Y.^2)./sqrt(Z); % Result matrix 1
R2 = sin(X.^2+Y.^2)./exp(Z); % Result matrix 2
R3 = cos(X.^2+Y.^(1/2)).*(Z.^(1/2)); % Result matrix 3
As of now, I'm calling 6 times the interp1 MATLAB function in order to interpolate (linearly) the 3 result matrices for a specific set of xVec, yVec and zVec values (e.g. xVec = 0.012, yVec = 0.37, and zVec = 1.45). I'm using the interp1 function as I was not able to find a better way of solving this (I think this could be possible with interp2 or interp3 MATLAB functions). By running the MATLAB profiler, I found that the calls to interp1 are taking a lot of time. Hence, I would like to know if there is a faster way of doing this (e.g. using less calls by using the interp2 or interp3 MATLAB function, or maybe even merging my 3 result matrices in a multidimensional array)?

As suggested in the comments, you can use gridded griddedInterpolant. I do not think that there is a standard procedure in MATLAB for optimisation of the interpolation of vector fields (although I did not look thoroughly enough to state this for a fact). Thus, I think you will have to use a different griddedInterpolant for each individual function R1, R2 and R3.
%% griddedInterpolant
[X, Y, Z] = ndgrid(xVec, yVec, zVec);
R1 = (X.^2+Y.^2)./sqrt(Z);
F = griddedInterpolant(X, Y, Z, R1, 'cubic');
figure
subplot(121)
s = slice(Y, X, Z, R1, 0.2, [-0.1 0.1], 2);
set(s, 'EdgeColor', 'none');
for n = 1 : length(s)
set(s(n),'alphadata', get(s(n), 'cdata'), 'facealpha', 'flat')
end
xlabel('y');
ylabel('x');
zlabel('z');
view([-130 30]);
title('Original data');
xqVec = linspace(min(xVec), max(xVec), numPoints); % Vector 1 interpolant
yqVec = linspace(min(yVec), max(yVec), numPoints); % Vector 2 interpolant
zqVec = linspace(min(zVec), max(zVec), numPoints); % Vector 3 interpolant
[Xq, Yq, Zq] = ndgrid(xqVec, yqVec, zqVec);
tic
R1q = F(Xq, Yq, Zq);
toc
subplot(122)
s = slice(Yq, Xq, Zq, R1q, 0.2, [-0.1 0.1], 2);
set(s, 'EdgeColor', 'none');
for n=1:length(s)
set(s(n), 'alphadata', get(s(n), 'cdata'), 'facealpha', 'flat')
end
xlabel('y');
ylabel('x');
zlabel('z');
view([-130 30]);
title('Gridded interpolant');
%% Query at a point
disp(['R1 at [0 0.21 2.1] is ' num2str(F(0, 0.21, 2.1))])

Related

MATLAB Update trisurf handle

I'm using a Delaunay triangularization to convert a scatter plot to a surface. To animate this plot, I want to update the trisurf handle instead of creating a new trisurf plot to reduce overhead and to increase the plotting speed.
Basically, in a for loop, I want to update the properties of the trisurf handle h to obtain the same plot that calling trisurf again would yield.
MWE
x = linspace(0,1,11);
y = x;
[X,Y] = meshgrid(x,y);
mag = hypot(X(:),Y(:)); % exemplary magnitude
T = delaunay(X(:),Y(:));
z = 0
h = trisurf(T, X(:), Y(:), z*ones(size(X(:))), mag, 'FaceColor', 'interp'); view([-90 90]);
for i = 1:10
% Compute new values for X, Y, z, and mag
% -> Update properties of handle h to redraw the trisurf plot instead
% of recalling the last line before the for loop again, e.g.,
% h.FaceVertexCData = ...
% h.Faces = ...
% h.XData = ...
end
You can change a few properties of the Patch object returned by trisurf():
for i = 1:9
% Compute new values for X, Y, z, and mag
% As an example:
x = linspace(0,1,11-i);
y = x;
[X,Y] = meshgrid(x,y);
mag = hypot(X(:),Y(:));
T = delaunay(X(:),Y(:));
z = i;
Z = z*ones(size(X)); %we could have just called `meshgrid()` with 3 arguments instead
% End recomputation
% Update trisurf() patch: option 1
set( h, 'Faces',T, 'XData',X(T).', 'YData',Y(T).', 'ZData',Z(T).', 'CData',mag(T).' );
pause(0.25); %just so we can see the result
% Update trisurf() patch: option 2
set( h, 'Faces',T, 'Vertices',[X(:) Y(:) Z(:)], 'FaceVertexCData',mag(:) );
pause(0.25); %just so we can see the result
end
where z is assumed to always be a scalar, just like in the original call to trisurf().
Q: Are these options equally fast?
A: I have run some tests (see code below) on my computer (R2019a, Linux) and found that, when the number of x/y-positions is a random number between 2 and 20, multiple set() calls using Vertices can be some 20% faster than set() calls using XData and related properties, and that these strategies are about an order of magnitude faster than multiple trisurf() calls. When the number of x/y-positions is allowed to vary from 2 to 200, however, run times are about the same for the three approaches.
Nruns=1e3;
Nxy_max=20;
for i=1:Nruns
if i==round(Nruns/10)
tic(); %discard first 10% of iterations
end
x = linspace(0,1,randi(Nxy_max-1)+1); %randi([2,Nxy_max]) can be a bit slower
[X,Y,Z] = meshgrid(x,x,randn());
mag = hypot(X(:),Y(:));
T = delaunay(X(:),Y(:));
trisurf(T, X(:), Y(:), Z(:), mag, 'FaceColor', 'interp');
view([-90 90]);
end
tmean_trisurf=1e3*toc()/(Nruns-round(Nruns/10)+1), %in [ms]
h=trisurf(T, X(:), Y(:), Z(:), mag, 'FaceColor', 'interp');
view([-90 90]);
for i=1:Nruns
if i==round(Nruns/10)
tic();
end
x = linspace(0,1,randi(Nxy_max-1)+1);
[X,Y,Z] = meshgrid(x,x,randn());
mag = hypot(X(:),Y(:));
T = delaunay(X(:),Y(:));
set( h, 'Faces',T, 'XData',X(T).', 'YData',Y(T).', 'ZData',Z(T).', 'CData',mag(T).' );
end
tmean_xyzdata=1e3*toc()/(Nruns-round(Nruns/10)+1), %in [ms]
for i=1:Nruns
if i==round(Nruns/10)
tic();
end
x = linspace(0,1,randi(Nxy_max-1)+1);
[X,Y,Z] = meshgrid(x,x,randn());
mag = hypot(X(:),Y(:));
T = delaunay(X(:),Y(:));
set( h, 'Faces',T, 'Vertices',[X(:) Y(:) Z(:)], 'FaceVertexCData',mag(:) );
end
tmean_vertices=1e3*toc()/(Nruns-round(Nruns/10)+1), %in [ms]

How do you find an equation of a plane that best approximates 3 dimensional data in MATLAB?

I have the following 3 dimensional data in MATLAB:
tau = [6e-9 30e-12 6e-9 30e-12];
E=[1e-3 50e-6 .01 1e-3];
k=[6.93774E-08 1.23666E-08 4.45261E-08 1.90789E-08];
plot3(tau, E, k,'*'); xlabel('tau (s)'); ylabel('Energy (J)'); zlabel('k');
You can see the plot looks like this:
How do you find the equation of the plane that approximates this data (i.e. k is a function of tau and E, so I'm looking for a formula for k(tau,E) = that best fits the data in least squares sense.).
Is there an easy way to do this in MATLAB?
You can do a simple least squares solution:
tau = [6e-9 30e-12 6e-9 30e-12];
E = [1e-3 50e-6 .01 1e-3];
k = [6.93774E-08 1.23666E-08 4.45261E-08 1.90789E-08];
A = [tau; E; ones(size(E))]';
b = k';
beta = A\b;
[X, Y] = meshgrid(linspace(min(tau), max(tau), 20),...
linspace(min(E), max(E), 20));
Z = beta(1)*X + beta(2)*Y + beta(3);
plot3(tau, E, k,'o', 'markerfacecolor', 'b');
xlabel('tau (s)'); ylabel('Energy (J)'); zlabel('k'); hold on;
mesh(X, Y, Z, 'edgecolor', 'k');

How can I fill an area below a 3D graph in MATLAB?

I created the following 3d plot in MATLAB using the function plot3:
Now, I want to get a hatched area below the "2d sub-graphs" (i.e. below the blue and red curves). Unfortunately, I don't have any idea how to realize that.
I would appreciate it very much if somebody had an idea.
You can do this using the function fill3 and referencing this answer for the 2D case to see how you have to add points on the ends of your data vectors to "close" your filled polygons. Although creating a pattern (i.e. hatching) is difficult if not impossible, an alternative is to simply adjust the alpha transparency of the filled patch. Here's a simple example for just one patch:
x = 1:10;
y = rand(1, 10);
hFill = fill3(zeros(1, 12), x([1 1:end end]), [0 y 0], 'b', 'FaceAlpha', 0.5);
grid on
And here's the plot this makes:
You can also create multiple patches in one call to fill3. Here's an example with 4 sets of data:
nPoints = 10; % Number of data points
nPlots = 4; % Number of curves
data = rand(nPoints, nPlots); % Sample data, one curve per column
% Create data matrices:
[X, Y] = meshgrid(0:(nPlots-1), [1 1:nPoints nPoints]);
Z = [zeros(1, nPlots); data; zeros(1, nPlots)];
patchColor = [0 0.4470 0.7410]; % RGB color for patch edge and face
% Plot patches:
hFill = fill3(X, Y, Z, patchColor, 'LineWidth', 1, 'EdgeColor', patchColor, ...
'FaceAlpha', 0.5);
set(gca, 'YDir', 'reverse', 'YLim', [1 nPoints]);
grid on
And here's the plot this makes:

Fit bimodal normal distribution to a vector of values, not its histogram

I would like to fit a bimodal normal distribution to data that looks bimodally distributed, such as the example below (plot(x)):
From the MATLAB docs I thought about using the mle function with a function handle to a mixture of two Gaussians:
#(x,p,mu1,mu2,sigma1,sigma2)p*normpdf(x,mu1,sigma1)+(1-p)*normpdf(x,mu2,sigma2)
However, the mle function fits to the histogram of x, while I want an approximation to x itself. How could I achieve this?
The idea is to create array y whose histogram looks like your function x (which should be positive everywhere):
%// Calculate
N = numel(x);
xi = fix(x/max(x)*100); % Limit the memory damage
yp = arrayfun(#(n) n*ones(1,xi(n)), 1:N, 'UniformOutput', false);
y = [yp{:}];
%// Visually inspect
ax = axes('Parent', figure());
plot(ax, xi); hold(ax, 'on');
hist(ax, y, N);
Matlab has a builtin bimodal fit
f =#(A,m,s,x) A(1) * exp(-((x-m(1))/s(1)).^2) + A(2) * exp(-((x-m(2))/s(2)).^2);
g =#(x) f([5, 10], [1, 10], [3, 5], x);
x = (-20:0.01:20)';
y = g(x) + 0.25*(rand(size(x)) - 0.5);
opts = fitoptions( 'Method', 'NonlinearLeastSquares' );
opts.Display = 'Off';
[fitresult, gof] = fit( x, y, 'gauss2', opts );
plot( fitresult, x, y );
%u can use the function
histfit(yourdata,nbins,'Kernel','normal');
%sometimes the it doesnt converge ; in those case u can resort to distributionFitter app
distributionFitter(yourdata);
%select non-parametric ; then normal

plotting a bullet-nose curves

I would like to plot this function of Two Variables you can find it here
$$z^2=t(t-i) \Longleftrightarrow x^2+y^2=4x^2y^2 \Longleftrightarrow y=\dfrac{\pm x}{\sqrt{4x^2-1}} \mbox{ with } |x|>\frac{1}{2}$$
would someone show me step by step how to plot this in matlab
is there any script or toolbox in http://www.mathworks.com/matlabcentral/fileexchange
which make plot of that kind of curves quickly
this is by geogebra
This is by wolframe
You can use symbolic variables with ezplot.
syms x y % makes symbolic variables
h1 = ezplot('-4*x^2*y^2+x^2+y^2'); % plots the equation
axis equal
set(h1, 'Color', 'k');
Or you can define a function,
f = #(x,y) -4.*x.^2.*y.^2+x.^2+y.^2;
h1 = ezplot(f);
set(h1, 'Color', 'k');
It won't be easy to have the axis in the middle, I hope it's not necessary to have that.
Edit
You can download oaxes here
syms x y
h1 = ezplot('-4*x^2*y^2+x^2+y^2');
axis equal
set(h1, 'Color', 'm');
oaxes('TickLength',[3 3],'Arrow','off','AxisLabelLocation','side',...
'LineWidth',1)
Edit
For 3D plot try this,
% First line provides a grid of X and Y varying over -5 to 5 with .5 as step-size
[X,Y] = meshgrid(-5:.5:5);
% instead of "=0", Z takes the values of the equation
Z = -4 .* X.^2 .* Y.^2 + X.^2 + Y.^2;
surf(X,Y,Z) % makes a 3D plot of X,Y,Z
You can also try contourf(X,Y,Z) for 2D plot.