Take fitted data from fit object - matlab

I use the following example taken from the site that describes fit. Returns an
object. Is it possible to take the data that refer to the fitted surface?
load franke
sf = fit([x, y],z,'poly23')
plot(sf,[x,y],z)
Thanks!

Here is a way to do it; but there is probably a cleaner one:
After getting your sf object, you can access its methods like so:
MethodName(sf)
See here for the list of available methods
So let's say you wish to plot the surface using a handle for the plot:
hPlot = plot(sf)
Then you can fetch the XData, YData and ZData using the handles like so:
X = get(hPlot,'XData')
Y = get(hPlot,'YData')
Z = get(hPlot,'ZData')
Might be a it cumbersome but it works. Note that you can also fetch the coefficients of the fitted surface like so:
coeffvalues(sf)
and the formula used to generate it:
formula(sf)
Therefore you could generate X, Y data and create Z values using meshgrid for example and you could then modify the surface as you wish.
EDIT Here is how you could create your own surface using the coefficients and the formula. Here I create an anonymous function with two input arguments (x and y) and use it to generate z values to plot. From the data obtained using plot(sf) I used x = 1:0.01:0.01:1 and y = 500:500:3000 but you could obviously change them.
I entered the formula manually in the function handle but there has to be a better way; I'm a bit in a hurry so I did not looked further into that but you could extract every element of the formula and multiply it by the right coefficient to automatically generate the formula.
Here is the whole code:
clear
clc
close all
load franke
sf = fit([x, y],z,'poly23')
c = coeffvalues(sf)
F = formula(sf)
%// Generate x and y values.
[x,y] = meshgrid(500:100:3000,0.01:.01:1);
%// There should be a better approach than manually entering the data haha.
%// Maybe use eval or feval.
MyFun = #(x,y) (c(1) + c(2)*x + c(3)*y +c(4)*x.^2 + c(5)*x.*y + c(6)*y.^2 + c(7)*(x.^2).*y + c(8)*x.*y.^2 + c(9)*y.^3);
%// Generate z data to create a surface
z = (MyFun(x,y));
figure
subplot(1,2,1)
plot(sf)
title('Plot using sf','FontSize',18)
subplot(1,2,2)
surf(x,y,z)
title('Plot using MyFun','FontSize',18)
Output:

[I know this is many years later, but I thought I'd add this for future visitors looking for answers]
There is a much simpler way to do this - use feval, or the implicit shortcuts to it by calling the fittype object itself. It did take me a little digging to find this when I needed it, it isn't particularly obvious.
From the feval MATLAB documentation:
Standard feval syntax:
y = feval(cfun,x)
z = feval(sfun,[x,y])
z = feval(sfun,x,y)
y = feval(ffun,coeff1,coeff2,...,x)
z = feval(ffun,coeff1,coeff2,...,x,y)
You can use feval to evaluate fits, but the following simpler syntax is recommended to evaluate these objects, instead of calling feval directly. You can treat fit objects as functions and call feval indirectly using the following syntax:
y = cfun(x) % cfit objects;
z = sfun(x,y) % sfit objects
z = sfun([x, y]) % sfit objects
y = ffun(coef1,coef2,...,x) % curve fittype objects;
z = ffun(coef1,coef2,...,x,y) % surface fittype objects;

Related

Get the points from a MatLab fit object plot

I am a Matlab amateur so please bear with me -
I currently use Matlab to fit a complex equation to two-dimensional data. Right now I have a program which uses f = fit(xdata, ydata, function, options) to generate a fit object.
I can then use confint(f) and f.parameter etc. to get the fitted coefficients and confidence intervals, and I can use plot(f,x,y) to make a plot of the data and the fit.
From that point on the only way I know how to get the points which were plotted is to use the brush(?) tool and select all of the line, then copy the data to clipboard and paste it into excel or some such thing. I would much rather get those points directly from Matlab, perhaps into an array, but I have no idea how.
Can any MatLab veteran tell me if what I want is even possible? It would be very difficult due to the complexity of my equation to plot those points myself, but I will if need be (it can take ~30 minutes to do this fit and my computer is no slouch).
Since you have not shared any code or data, I use an example from MATLAB documentation:
load franke
f = fit([x, y],z,'poly23');
plot(f,[x,y],z)
So as you can sew, it first loads a dataset including x,y,z vectors. Then fits a surface to the data using 'poly23'. In your case it can be different sets of vectors and function and still as you said you will get the f function.
Now we can take a look at the function f
>> f
Linear model Poly23:
f(x,y) = p00 + p10*x + p01*y + p20*x^2 + p11*x*y + p02*y^2 + p21*x^2*y
+ p12*x*y^2 + p03*y^3
Coefficients (with 95% confidence bounds):
p00 = 1.118 (0.9149, 1.321)
p10 = -0.0002941 (-0.000502, -8.623e-05)
p01 = 1.533 (0.7032, 2.364)
p20 = -1.966e-08 (-7.084e-08, 3.152e-08)
p11 = 0.0003427 (-0.0001009, 0.0007863)
p02 = -6.951 (-8.421, -5.481)
p21 = 9.563e-08 (6.276e-09, 1.85e-07)
p12 = -0.0004401 (-0.0007082, -0.0001721)
p03 = 4.999 (4.082, 5.917)
It shows you the form of the function and the coefficients. So you can use it as follows:
zz = f(x,y);
To make sure you can plot the data again:
figure;
scatter3(x,y,zz,'.k');
hold on
scatter3(x,y,z,'.');
When you call f = fit(xdata, ydata, function, options), function name decides the equation. See list of official equations.
Simply iterate through data points and compute results using corresponding polynomial. So in your case lets say if function=poly2 you'll be doing computation as follows:
#Fit your data
f = fit([xdata, ydata],'poly2');
#Print name of coefficients (Just for Verification)
coeffnames(f)
#Fetch values of coefficients like p1, p2, ...
p = coeffvalues(c)
#Compute output points from min(xdata) to max(xdata) spaced at deltaX
deltaX = 0.1;
x = [min(xdata):deltaX:max(xdata)];
Y = p(1)*x^2+p(2)*x+p(3); #This is equation for function
I understand there can be alternate complex Java code to iterate through objects on a matlab figure and plot its value but using equations is a quick and valid approach.

What interpolation technique does Matlab plot function use to show the data?

It seems to be very basic question, but I wonder when I plot x values against y values, what interpolation technique is used behind the scene to show me the discrete data as continuous? Consider the following example:
x = 0:pi/100:2*pi;
y = sin(x);
plot(x,y)
My guess is it is a Lagrangian interpolation?
No, it's just a linear interpolation. Your example uses a quite long dataset, so you can't tell the difference. Try plotting a short dataset and you'll see it.
MATLAB's plot performs simple linear interpolation. For finer resolution you'd have to supply more sample points or interpolate between the given x values.
For example taking the sinus from the answer of FamousBlueRaincoat, one can just create an x vector with more equidistant values. Note, that the linear interpolated values coincide with the original plot lines, as the original does use linear interpolation as well. Note also, that the x_ip vector does not include (all) of the original points. This is why the do not coincide at point (~0.8, ~0.7).
Code
x = 0:pi/4:2*pi;
y = sin(x);
x_ip = linspace(x(1),x(end),5*numel(x));
y_lin = interp1(x,y,x_ip,'linear');
y_pch = interp1(x,y,x_ip,'pchip');
y_v5c = interp1(x,y,x_ip,'v5cubic');
y_spl = interp1(x,y,x_ip,'spline');
plot(x,y,x_ip,y_lin,x_ip,y_pch,x_ip,y_v5c,x_ip,y_spl,'LineWidth',1.2)
set(gca,'xlim',[pi/5 pi/2],'ylim',[0.5 1],'FontSize',16)
hLeg = legend(...
'No Interpolation','Linear Interpolation',...
'PChip Interpolation','v5cubic Interpolation',...
'Spline Interpolation');
set(hLeg,'Location','south','Fontsize',16);
By the way..this does also apply to mesh and others
[X,Y] = meshgrid(-8:2:8);
R = sqrt(X.^2 + Y.^2) + eps;
Z = sin(R)./R;
figure
mesh(Z)
No, Lagrangian interpolation with 200 equally spaced points would be an incredibly bad idea. (See: Runge's phenomenon).
The plot command simply connects the given (x,y) points by straight lines, in the order given. To see this for yourself, use fewer points:
x = 0:pi/4:2*pi;
y = sin(x);
plot(x,y)

How do I plot relations in matlab?

I want to plot relations like y^2=x^2(x+3) in MATLAB without using ezplot or doing algebra to find each branch of the function.
Does anyone know how I can do this? I usually create a linspace and then create a function over the linspace. For example
x=linspace(-pi,pi,1001);
f=sin(x);
plot(x,f)
Can I do something similar for the relation I have provided?
What you could do is use solve and allow MATLAB's symbolic solver to symbolically solve for an expression of y in terms of x. Once you do this, you can use subs to substitute values of x into the expression found from solve and plot all of these together. Bear in mind that you will need to cast the result of subs with double because you want the numerical result of the substitution. Not doing this will still leave the answer in MATLAB's symbolic format, and it is incompatible for use when you want to plot the final points on your graph.
Also, what you'll need to do is that given equations like what you have posted above, you may have to loop over each solution, substitute your values of x into each, then add them to the plot.
Something like the following. Here, you also have control over the domain as you have desired:
syms x y;
eqn = solve('y^2 == x^2*(x+3)', 'y'); %// Solve for y, as an expression of x
xval = linspace(-1, 1, 1000);
%// Spawn a blank figure and remember stuff as we throw it in
figure;
hold on;
%// For as many solutions as we have...
for idx = 1 : numel(eqn)
%// Substitute our values of x into each solution
yval = double(subs(eqn(idx), xval));
%// Plot the points
plot(xval, yval);
end
%// Add a grid
grid;
Take special care of how I used solve. I specified y because I want to solve for y, which will give me an expression in terms of x. x is our independent variable, and so this is important. I then specify a grid of x points from -1 to 1 - exactly 1000 points actually. I spawn a blank figure, then for as many solutions to the equation that we have, we determine the output y values for each solution we have given the x values that I made earlier. I then plot these on a graph of these points. Note that I used hold on to add more points with each invocation to plot. If I didn't do this, the figure would refresh itself and only remember the most recent call to plot. You want to put all of the points on here generated from all of the solution. For some neatness, I threw a grid in.
This is what I get:
Ok I was about to write my answer and I just saw that #rayryeng proposed a similar idea (Good job Ray!) but here it goes. The idea is also to use solve to get an expression for y, then convert the symbolic function to an anonymous function and then plot it. The code is general for any number of solutions you get from solve:
clear
clc
close all
syms x y
FunXY = y^2 == x^2*(x+3);
%//Use solve to solve for y.
Y = solve(FunXY,y);
%// Create anonymous functions, stored in a cell array.
NumSol = numel(Y); %// Number of solutions.
G = cell(1,NumSol);
for k = 1:NumSol
G{k} = matlabFunction(Y(k))
end
%// Plot the functions...
figure
hold on
for PlotCounter = 1:NumSol
fplot(G{PlotCounter},[-pi,pi])
end
hold off
The result is the following:
n = 1000;
[x y] = meshgrid(linspace(-3,3,n),linspace(-3,3,n));
z = nan(n,n);
z = (y .^ 2 <= x .^2 .* (x + 3) + .1);
z = z & (y .^ 2 >= x .^2 .* (x + 3) - .1);
contour(x,y,z)
It's probably not what you want, but I it's pretty cool!

How to integrate over a discrete 2D surface in MATLAB?

I have a function z = f(x, y), where z is the value at point (x, y). How may I integrate z over the x-y plane in MATLAB?
By function above, I actually mean I have something similar to a hash table. That is, given a (x, y) pair, I can look up the table to find the corresponding z value.
The problem would be rather simple, if the points were uniformly distributed over x-y plane, in which case I can simply sum up all the z values, multiply it with the bottom area, and finally divide it by the number of points I have. However, the distribution is not uniform as shown below. So I am actually asking for the computation method that minimises the error.
The currently accepted answer will only work for gridded data. If your data is scattered you can use the following approach instead:
scatteredInterpolant + integral2:
f = scatteredInterpolant(x(:), y(:), z(:), 'linear');
int = integral2(#(x,y) f(x,y), xmin, xmax, ymin, ymax);
This defines the linear interpolant f of the data z(i) = f(x(i),y(i)) and uses it as an argument to integral2. Note that ymin and ymax, instead of doubles, can be function handles depending on x. So usually you will be integrating rectangles, but this could be used for integration regions a bit more complicated.
If your integration area is rather complicated or has holes, you should consider triangulating your data.
DIY using triangulation:
Let's say your integration area is given by the triangulation trep, which for example could be obtained by trep = delaunayTriangulation(x(:), y(:)). If you have your values z corresponding to z(i) = f(trep.Points(i,1), trep.Points(i,2)), you can use the following integration routine. It computes the exact integral of the linear interpolant. This is done by evaluating the areas of all the triangles and then using these areas as weights for the midpoint(mean)-value on each triangle.
function int = integrateTriangulation(trep, z)
P = trep.Points; T = trep.ConnectivityList;
d21 = P(T(:,2),:)-P(T(:,1),:);
d31 = P(T(:,3),:)-P(T(:,1),:);
areas = abs(1/2*(d21(:,1).*d31(:,2)-d21(:,2).*d31(:,1)));
int = areas'*mean(z(T),2);
If you have a discrete dataset for which you have all the x and y values over which z is defined, then just obtain the Zdata matrix corresponding to those (x,y) pairs. Save this matrix, and then you can make it a continuous function using interp2:
function z_interp = fun(x,y)
z_interp = interp2(Xdata,Ydata,Zdata,x,y);
end
Then you can use integral2 to find the integral:
q = integral2(#fun,xmin,xmax,ymin,ymax)
where #fun is your function handle that takes in two inputs.
I had to integrate a biavariate normal distribution recently in MatLab. The idea is very simple. Matlab defines a surface through a meshgrid, so from x, y you need to do this:
x = -10:0.05:10;
y = x;
[X,Y] = meshgrid(x',y');
...for example. Then, let's call FX the function that defines the value at each point of the surface. To calculate the integral you just need to do this:
surfint = zeros(length(X),1);
for a = 1:length(X)
surfint(a,1) = trapz(x,FX(:,a));
end
trapz(x, surfint)
For me, this is the simplest way.

How to draw a circular 3D plot in matlab

I want to plot this function in matlab : sin(4*x)*cos(4*y) on a disk
This is how i proceeded :
syms x y;
f=#(x,y) sin(4*x)*cos(4*y);
ezmesh(f,'circ')
This method works with f=#(x,y) sin(2*x)*cos(2*y);
but with a more quickly varying function like f=#(x,y) sin(4*x)*cos(4*y); ezmesh mistakes these variations for discontinuities.
the problem is i can't use the 'circ' parameter and increase the number of points that ezmesh uses at the same time (ezmesh didn't accept it)
Is there any other way ?
I'm not sure if it can be done by adding another parameter. However, if you want a quick-and-dirty way, here you go:
x = -2*pi:0.1:2*pi;
y = -2*pi:0.1:2*pi;
[xx, yy] = meshgrid(x,y);
zz = sin(4*xx).*cos(4*yy);
zz(xx.^2 +yy.^2 >(2*pi)^2) = 0;
surf(xx,yy,zz);
Which produces: