How to fit a curve to a set of data for same x values? - scipy

I have some curves from the lab tests on material. each set of data has different lenghts. i am willing to fit a curve to these data.
Lets start with data having same lenght: y1 y2 y3 with same x values.
import numpy as np
import matplotlib.pyplot as plt
def my_function(x,y):
curve = np.polyfit(x, y, 4)
poly = np.poly1d(curve)
new_x = np.arange(x[0],x[-1],1)
new_y= poly(new_x)
plt.plot(new_x, new_y)
plt.scatter(x, y)
print(poly)
x = [0, 5.25, 10.5, 21, 31.5, 42, 52.5, 63, 73.5, 84, 94.5, 99.75, 105]
y1=[0.2535,0.3552,0.456,0.489,0.5265,0.58384,1.87616,2.87328,2.55184,2.66992,2.8208,3.09632,3.51616]
y2=[0.116112,0.425088,0.582528,0.70192,1.07584,2.41408,3.75232,4.61824,2.55184,2.66992,2.8208,3.09632,3.51616]
y3=[0.389664,1.166368,1.60392,2.05984,2.788,4.02784,5.0184,5.60224,2.55184,2.66992,2.8208,3.09632,3.51616]
ylist = [ y1, y2, y3]
for y in ylist:
my_function(x,y)
My final goal is to do this for pairs of y and x, which their lenghts are different from other pairs of data.
what im expecting is like this:
enter image description here

I may be misunderstanding your question but nothing in your code presumes that all your y's have to have the same length. This works for me:
import numpy as np
import matplotlib.pyplot as plt
def my_function(x,y):
curve = np.polyfit(x, y, 4)
poly = np.poly1d(curve)
new_x = np.arange(x[0],x[-1],1)
new_y= poly(new_x)
plt.plot(new_x, new_y)
plt.scatter(x, y)
print(poly)
x1 = [0, 5.25, 10.5, 21, 31.5, 42, 52.5, 63, 73.5, 84, 94.5, 99.75, 105]
x2 = [0, 5.25, 10.5, 21, 31.5, 42, 52.5, 63, 73.5, 84, 94.5, 99.75]
x3 = [0, 5.25, 10.5, 21, 31.5, 42, 52.5, 63, 73.5, 84, 94.5]
y1=[0.2535,0.3552,0.456,0.489,0.5265,0.58384,1.87616,2.87328,2.55184,2.66992,2.8208,3.09632,3.51616]
y2=[0.116112,0.425088,0.582528,0.70192,1.07584,2.41408,3.75232,4.61824,2.55184,2.66992,2.8208,3.09632]
y3=[0.389664,1.166368,1.60392,2.05984,2.788,4.02784,5.0184,5.60224,2.55184,2.66992,2.8208]
ylist = [ y1, y2, y3]
xlist = [ x1, x2, x3]
for x, y in zip(xlist, ylist):
my_function(x,y)
Edit: From the clarification in the comment
the goal is to fit one curve for all three y1 y2 y3 with their corresponding x1 x2 x3 curves
So all points in the curves defined by (x1, y1), (x2, y2), (x3, y3), ... should be fit to a single polynomial.
This can be done by simply concatenating the vectors containing the data:
x_tot = np.concatenate((x1, x2, x3))
y_tot = np.concatenate((y1, y2, y3))
my_function(x_tot,y_tot)
Which results in:
Note that the (x, y) arrays don't have to be the same length. In case that y1, y2, ..., share the same x, the concatenation should be x_tot = np.concatenate((x, x, x))

Related

How to find y value of interpolated spline at a desired x value?

How to extract the y value from spline at a desired x value. For example # x= 0.25
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import splev, splrep
x = np.linspace(0, 10, 10)
y = np.sin(x)
spl = splrep(x, y)
x2 = np.linspace(0, 10, 5)
y2 = splev(x2, spl)
plt.plot(x, y, 'o', x2, y2)
plt.show()
Well, you are already doing this by calling splev(x,tck). This outputs an array with the y values at the given x values using the spline described by tck. (In your case, x is given by np.linspace() and tck is the output of np.splrep().)
If you only want to know what the value at e.g. x=.25 is, you would write y3=splev(0.25, spl). Maybe take a look at the documentation for more details: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.splev.html

How to express multiple linear regression graphically in MATLAB?

I am trying to generate the same plot as the one shown below,
, and I have written the following piece of code in MATLAB,
x1 = [0, 0, 1, 1];
x2 = [0, 1, 0, 1];
Y = [4, 3, 2, 4];
plot3(x1,x2,Y,'o','Color','r','MarkerSize',10, 'MarkerFaceColor', 'r')
hold on
[x y] = meshgrid(0:0.1:2, 0:0.1:2);
z = 1.25 + 2.5 * x + 1.5 * y;
surf(x, y, z,'FaceAlpha',0.5)
xlabel('x1');ylabel('x2');zlabel('y');
hold off
grid on
Would you please tell me how I can plot a line that connects the data point with its corresponding value of the generated surface for the same plot I generated with MATLAB.
Many thanks for your time.
I added a loop within the "hold" portion of your code.
x1 = [0, 0, 1, 1];
x2 = [0, 1, 0, 1];
Y = [4, 3, 2, 4];
plot3(x1,x2,Y,'o','Color','r','MarkerSize',10, 'MarkerFaceColor', 'r')
hold on
[x y] = meshgrid(0:0.1:2, 0:0.1:2);
z = 1.25 + 2.5 * x + 1.5 * y;
surf(x, y, z,'FaceAlpha',0.5)
xlabel('x1');ylabel('x2');zlabel('y');
for ii=1:numel(Y)
plot3( [x1(ii),x1(ii)], [x2(ii),x2(ii)], [Y(ii),1.25+2.5*x1(ii)+1.5*x2(ii)] );
end
hold off
grid on
Also, currently your surface z is hard-coded, therefore the code for the vertical line is hard-coded as well. But once you estimate your parameters for the regression, you could just as easily dynamically adjust the surface and the vertical lines.

Using Matlab to get maximum values from many polyfitted curves in one figure

x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
z1 = [1, 4, 9, 16, 25, 36, 49, 36, 25, 16, 8, 1];
z2 = [1, 5, 10, 17, 26, 38, 26, 17, 10, 9, 7, 1];
z3 = [1, 8, 18, 30, 40, 30, 18, 8, 7, 4, 3, 1];
plot(x, z1, '*');
hold on;
p1 = polyfit(x, z1, 5);
z1fit = polyval(p1, x);
plot(x, z1fit);
hold on;
plot(x, z2, '*');
p2 = polyfit(x, z2, 5);
z2fit = polyval(p2, x);
plot(x, z2fit);
hold on;
plot(x, z3,'*');
p3 = polyfit(x, z3, 5);
z3fit = polyval(p3, x);
plot(x, z3fit);
My question is, how to find every maximum value of each curve and display them? The maximum points are not the maximum values that I gave , It should be the peak points after fitting. I can simply read these peak points from the plotted figure, just want to know how to get the exact coordinate of the highest peak of the polynomial fit and return them. The degree of n (in my code 5) from polyfit is changeable.
To get the exact value of the maximum in the range of x, you can use the optimization toolbox.
x=[1,2,3,4,5,6,7,8,9,10,11,12];
z1=[1,4,9,16,25,36,49,36,25,16,8,1];
p1=polyfit(x, z1, 5);
fun = #(x) -polyval(p1,x);
x_max = fminbnd(fun,x(1),x(end))
figure; hold on;
plot(x,z1,'*');
fplot(#(x) polyval(p1,x),[x(1) x(end)],':');
plot(x_max,polyval(p1,x_max),'o');
legend('data','fit','max')
Use the polyfit function to get the coefficients of the fitted polynomial, use the polyval function to create a function handle to the polynomial you created and the fminbnd to "Find minimum of single-variable function on fixed interval". With the function handle, you can use the fplot function to plot the fit.
Edit:
If you want to calculate and plot the fitted curves in the same figure, you can:
x=[1,2,3,4,5,6,7,8,9,10,11,12];
z1 = [1, 4, 9, 16, 25, 36, 49, 36, 25, 16, 8, 1];
z2 = [1, 5, 10, 17, 26, 38, 26, 17, 10, 9, 7, 1];
z3 = [1, 8, 18, 30, 40, 30, 18, 8, 7, 4, 3, 1];
z = [z1;z2;z3];
figure; hold on;
for ii=1:size(z,1)
p1=polyfit(x, z(ii,:), 5);
fun = #(x) -polyval(p1,x);
x_max = fminbnd(fun,x(1),x(end))
plot(x,z(ii,:),'*');
fplot(#(x) polyval(p1,x),[x(1) x(end)],':');
plot(x_max,polyval(p1,x_max),'o');
end
The result, however, will not be that good, because you will have a lot of information in the same figure. Depending on what you want, that may be good. But I suggest you plot on different figures different data, maybe using subplots.

Plotting four variables u = f(x, y, z) with ranges of x, y, z in Matlab

I'm trying to plot four variables (x, y, z, u) in a 3D space.
Below I defined u = f(x,y,z) = (x-y)/z and ranges for x, y and z.
Then I used the scatter3 function for plotting.
But the linspace command only returned
u1 = f(x1, y1, z1)
u2 = f(x2, y2, z2)
...
I wanted to plot my variables so that I would get values of u for all x, y and z, so as well as u_i = f(x_i, y_i, z_i), I want:
u112 = f(x1, y1, z2)
u121 = f(x1, y2, z1)
...
Which function do I need to use for this?
Full code:
z = linspace(1,2,50);
y = linspace(0,0.5,50);
x = linspace(-1,1,50);
f = (x-y)./z;
scatter3(x,y,z,5,f,'filled')
for i=1:50
if f(i)<0
scatter3(x,y,z,5,f,'r','filled');
else
scatter3(x,y,z,5,f,'b','filled');
end
end
You need to pass your x, y, and z vectors to meshgrid to have it generate points to fill the whole 3-D volume:
z = linspace(1, 2, 50);
y = linspace(0, 0.5, 50);
x = linspace(-1, 1, 50);
[X, Y, Z] = meshgrid(x, y, z);
f = (X-Y)./Z;
These will be 50-by-50-by-50 matrices. To plot them with scatter3 you will need to reshape them into column vectors using the colon operator:
scatter3(X(:), Y(:), Z(:), 5, f(:), 'filled');
If you'd like to plot negative values of f as red and positive values as blue, you can call scatter3 like so and add a jet colormap (no loops necessary):
scatter3(X(:), Y(:), Z(:), 5, (f(:) < 0), 'filled');
colormap(jet);

Contour Line and Surface Matlab

I want to produce a surface plot with a predefined contour line on the surface, in Matlab. I have already produced the plot in Mathematica, and want to create the equivalent figure in Matlab.
With the following functions I defined a surface
k2[G_, V_] = Sqrt[G]*Exp[-V];
k1[G_] = Sqrt[G]*Exp[-10];
L1[G_, V_] = -0.5*(k1[G_] + 2*k2[G, V]) + 0.5*Sqrt[k1[G_]^2 + 4*k2[G, V]^2];
and a parametric curve over the surface
hike=ParametricPlot3D[{10, 0, 0} + {x^2, x, -(1/L1[10 + x^2, x])}, {x, 0, 12},PlotStyle -> Directive[Thick, Red]];
hikeHeight=ParametricPlot3D[{10, 0, 0} + {x^2,x, -z*(1/L1[10 + x^2, x])}, {x, 0, 12}, {z, 0, 1},PlotStyle -> Directive[Gray], Mesh -> None];
Then I plot the surface and the contour line together:
surf= Plot3D[-1/L1[G, V], {G, 10, 100}, {V, 0, 12}];
Show[surf, hike, hikeHeight, AxesLabel -> {G, V,Z}, Boxed -> False]
What is the process for evaluating the function and producing the same plot in Matlab?
This how far i get with my matlab attempt
[X,Y,Z] = peaks(25);
curvX=diag(X);
curvY=diag(Y);
curvZ=diag(Z);
nn = 401;
xi = linspace(-3.0, 3.0, nn);
yi = xi;
[xi, yi] = meshgrid(xi, yi);
zi = interp2(X, Y, Z, xi, yi, 'spline');
figure()
surf(xi, yi, zi,'LineStyle', 'none', 'FaceColor', 'interp')
colormap(parula)
alpha 0.7
hold on
surf(diag(curvX),diag(curvY),diag(curvZ),'LineStyle', 'none')
the surface and the parametric curve are obviously not the same but the idea is the same to plot an slice of the surface
Let's start by defining the functions, as inline, vectorised function handles:
k2 = #(g, v)sqrt(g).*exp(-v);
k1 = #(g)sqrt(g).*exp(-10);
l1 = #(g, v) -.5 .* (k1(g) + 2.*k2(g, v)) + 0.5 * sqrt(k1(g).^2 + 4.*k2(g, v).^2);
Now we need to define a mesh, since Matlab isn't smart enough to do automatic discretisation like Mathematica:
nMeshPoints = 50;
vfG = linspace(10, 100, nMeshPoints);
vfV = linspace(0, 12, nMeshPoints);
[mfG, mfV] = ndgrid(vfG, vfV);
Ok, now we can evaluate the surface over the mesh, and make a surface plot:
hSurf = surf(mfG, mfV, -1./l1(mfG, mfV));
shading interp;
hold on;
hSurf.FaceAlpha = 0.5;
Now we need to build and plot your parametric line, also via explicit discretisation:
vfX = linspace(0, 12, nMeshPoints);
vfZ = linspace(0, 1, nMeshPoints);
vfLX = 10 + vfX.^2;
vfLY = vfX;
vfLZ = -(1 ./ l1(10 + vfX.^2, vfX));
vfLHeight = vfLZ .* vfZ;
plot3(vfLX, vfLY, vfLZ, 'r-');
plot3(vfLX, vfLY, vfLHeight, 'k-');
Now we can make the plot a little more beautiful:
xlim([10 100]);
ylim([0 12]);
zlim([0 20000]);
caxis([0 20000]);
xlabel('G');
ylabel('V');
zlabel('Z');
view([60, 30]);
The result: not quite as beautiful as Mathematica, but at least equivalent.