Creating a Plane of best fit from points - python

Is there a way to make a plane of best fit using matplotlib?
I'm trying to get a smooth curved plane or even just a flat one, but I'm unsure on how to do so.
My points are arranged as shown in the following image:
They are quite smooth, except for a few exceptions, which are mostly clear.
My current code is:
from mpl_toolkits import mplot3d
import matplotlib.pyplot as plt
from sklearn import linear_model
plt.style.use('seaborn-poster')
x = np.array([12.5, 10, 9.5, 7.5, 6])
y = np.array([30, 45, 50, 55, 60, 65])
z = np.array([
[62.13, 55.41, 54.49, 46.46, 42.13],
[67.11, 59.43, 56.39, 52.64, 41.89],
[82.89, 61.13, 57.30, 50.75, 43.02],
[73.31, 60.57, 57.17, 52.64, 41.73],
[78.11, 62.92, 63.40, 58.08, 48.69],
[83.96, 65.19, 60.22, 53.57, 44.22]
])
X, Y = np.meshgrid(x, y)
Z = z
x1, y1, z1 = X.flatten(), Y.flatten(), Z.flatten()
X_data = np.array([x1, y1]).reshape((-1, 2))
Y_data = z1
reg = linear_model.LinearRegression().fit(X_data, Y_data)
a1, a2, c = float(reg.coef_[0]), float(reg.coef_[1]), float(reg.intercept_)
fig = plt.figure(figsize = (9,9))
ax = plt.axes(projection='3d')
ax.grid()
ax.plot_surface(X, Y, z)
ax.scatter(X, Y, z, c = 'r', s = 50)
ax.set_title('Figure 1.21 - Plot of Final results')
ax.set_xlabel('Radius of Ball (mm)', labelpad=20)
ax.set_ylabel('Height from which ball was dropped (cm)', labelpad=20)
ax.set_zlabel('Diameter of ripple (mm)', labelpad=20)
plt.show()
I have the a1, a2 and c values using linear regression but how do I plot them?
Is linear regression going to give the right sort of result for this graph?
I'm quite new to matplotlib, so sorry if this seems obvious.

Related

Unexpected behavior for contourplot in polar coordinates - jagged contours

I wish to plot a bunch of points onto a polar plot. When I apply it with simulated data, it works. When I try the same with my real data it fails and I'm not sure why.
# First with simulated data
# The angles for each point
phi = np.linspace(0, math.pi*2, 40) # full circle
phi = np.concatenate([phi, phi, phi, phi]) # 4 full circles
# The radii
rho = np.array([0,1,2,3]) # the radii for each circle
rho = np.repeat(rho, 40)
assert phi.shape == rho.shape
# First just plot the points
plt.figure()
ax = plt.subplot(111, projection='polar')
ax.scatter(phi, rho, c=rho)
ax.set_ylim(0,4)
This appears to work. Next, I use the following to draw concentric contours around the origin. The Z property is set to the radii, i.e., points that equally far away from the origin should be grouped within a contour.
# Create a meshgrid from the points
X, Y = np.meshgrid(phi, rho)
plt.figure()
ax = plt.subplot(111, projection='polar')
ax.scatter(X, Y, c=Y)
CS = ax.contourf(X,Y, Y, 2, alpha=0.4)
ax.set_ylim(0,4)
This works exactly as I want it:
Next, I want to apply this to my real data. My actual data has millions of data points, but here's just a small sample to reproduce.
rho = np.array([0.38818333, 0.73367091, 0.42336148, 1.39013061, 0.31064486,0.34546275, 0.05445943, 0.85551576, 0.55174167, 1.42371249,0.17644804, 1.76221456, 0.64519126, 0.02408941, 1.43986863,0.72718428, 0.4262945 , 0.1355583 , 0.86319986, 0.71212376,0.14891707, 1.01624534, 1.26915981, 1.39384488, 0.09623481,0.92635469, 1.74757901, 0.15811954, 0.22052651, 0.30784166,0.92740352, 1.29621377, 0.29832842, 1.04442307, 1.36185399,0.42979785, 0.94402815, 0.3786981 , 0.75865969, 1.97273479,0.61140136, 0.71452862, 0.25793468, 1.1751275 , 1.53945948,0.64150917, 0.09274101, 0.52548715, 0.7932458 , 0.90292444])
phi = np.array([1.04208195, 4.67055389, 3.32909655, 1.18709268, 0.86036178,5.820191 , 4.30457004, 1.81242968, 0.64295926, 4.85684143,2.73937709, 3.22891963, 0.25822595, 0.69526782, 0.70709764,1.92901075, 3.44538869, 5.38541473, 0.95255568, 4.01519928,0.8503274 , 5.26774545, 4.07787945, 4.51718652, 0.3170884 ,2.1946835 , 3.12550771, 5.67275731, 1.0000195 , 1.82570239,5.62578391, 0.81923255, 2.00131474, 0.48190872, 4.78875363,5.60395833, 2.01674743, 2.13494958, 5.10829845, 0.95324309,1.59531506, 4.99145225, 6.19873491, 3.32802456, 1.15590926,0.52989939, 6.02205398, 3.66013508, 4.16276819, 2.60498467])
assert rho.shape == phi.shape # both are (50,)
plt.figure()
ax = plt.subplot(111, projection='polar')
ax.scatter(phi, rho, c=rho)
ax.set_ylim(0,3)
Of course, my real data has much more variation that the simulated circles above. Next, I try to draw the contours in the same method. However, this now fails:
# Create a meshgrid from the points
X, Y = np.meshgrid(phi, rho)
plt.figure(figsize=(10,10)) # a little bigger to see better
ax = plt.subplot(111, projection='polar')
ax.scatter(X, Y, c=Y)
CS = ax.contourf(X,Y, Y, 2, alpha=0.4)
ax.set_ylim(0,4)
This behaviour is due to the fact that rho and phi are not sorted. Let's see:
import matplotlib.pyplot as plt
import numpy as np
rho = np.array([0.38818333, 0.73367091, 0.42336148, 1.39013061, 0.31064486,0.34546275, 0.05445943, 0.85551576, 0.55174167, 1.42371249,0.17644804, 1.76221456, 0.64519126, 0.02408941, 1.43986863,0.72718428, 0.4262945 , 0.1355583 , 0.86319986, 0.71212376,0.14891707, 1.01624534, 1.26915981, 1.39384488, 0.09623481,0.92635469, 1.74757901, 0.15811954, 0.22052651, 0.30784166,0.92740352, 1.29621377, 0.29832842, 1.04442307, 1.36185399,0.42979785, 0.94402815, 0.3786981 , 0.75865969, 1.97273479,0.61140136, 0.71452862, 0.25793468, 1.1751275 , 1.53945948,0.64150917, 0.09274101, 0.52548715, 0.7932458 , 0.90292444])
phi = np.array([1.04208195, 4.67055389, 3.32909655, 1.18709268, 0.86036178,5.820191 , 4.30457004, 1.81242968, 0.64295926, 4.85684143,2.73937709, 3.22891963, 0.25822595, 0.69526782, 0.70709764,1.92901075, 3.44538869, 5.38541473, 0.95255568, 4.01519928,0.8503274 , 5.26774545, 4.07787945, 4.51718652, 0.3170884 ,2.1946835 , 3.12550771, 5.67275731, 1.0000195 , 1.82570239,5.62578391, 0.81923255, 2.00131474, 0.48190872, 4.78875363,5.60395833, 2.01674743, 2.13494958, 5.10829845, 0.95324309,1.59531506, 4.99145225, 6.19873491, 3.32802456, 1.15590926,0.52989939, 6.02205398, 3.66013508, 4.16276819, 2.60498467])
plt.figure(figsize=(10,10))
ax = plt.subplot(111, projection='polar')
ax.set_ylim(0,4)
ax.scatter(phi, rho, c=rho)
#phi.sort()
#rho.sort()
X, Y = np.meshgrid(phi, rho)
CS = ax.contourf(X, Y, Y, 2, alpha=0.4)
plt.show()
gives:
If you uncomment the sorting lines:
But now the contours look weird, because the base data does not the whole geometry of interest. So we can create same data just for the purpose of the filled contours, instead:
alfa = np.radians(np.linspace(0, 360, 60))
r = np.arange(0, np.max(rho)+np.max(rho)/60, np.max(rho)/60)
r, alfa = np.meshgrid(r, alfa)
ax.contourf(alfa, r, r, 2, alpha=0.4)
Giving:

interpolate curve between three values

I have the following script that plots a graph:
x = np.array([0,1,2])
y = np.array([5, 4.31, 4.01])
plt.plot(x, y)
plt.show()
The problem is, that the line goes straight from point to point, but I want to smooth the line between the points.
If I use scipy.interpolate.spline to smooth my data I got following result:
order = np.array([0,1,2])
y = np.array([5, 4.31, 4.01])
xnew = np.linspace(order.min(), order.max(), 300)
smooth = spline(order, y, xnew)
plt.plot(xnew, smooth)
plt.show()
But I want to have the same result like in that given example
If you use more points than 3 you will get the same result as in the linked question. There are many ways a spline of order 3 can go through 3 points.
But you may of course reduce the order to 2.
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import spline
x = np.array([0,1,2])
y = np.array([5, 4.31, 4.01])
plt.plot(x, y)
xnew = np.linspace(x.min(), x.max(), 300)
smooth = spline(x, y, xnew, order=2)
plt.plot(xnew, smooth)
plt.show()

Python: Plotting Evenly Spaced Spheres in Matplotlib

I'm trying to create a plot a bit like this:
Where there are spheres above all the minima.
The surface can be approximated with a sin(x)*sin(y) plot:
import numpy as np
import matplotlib.pyplot as plt
def func(x, y):
return np.sin(2*np.pi*x)*np.sin(2*np.pi*y) / 3
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = y = np.arange(-1.0, 1.0, 0.05)
X, Y = np.meshgrid(x, y)
zs = np.array([func(x,y) for x,y in zip(np.ravel(X), np.ravel(Y))])
Z = zs.reshape(X.shape)
ax.plot_surface(X, Y, Z, color="grey")
ax.set_zlim3d(-1,1)
plt.show()
However I'm unsure how to add evenly spaced spheres into this. Would anyone be able to help?
Using matplotlib one will inevitably run into problems of objects being hidden behind others. This is also stated in the matplotlib 3d FAQ and the recommendation is to use mayavi.
In mayavi the solution would look like this:
from mayavi import mlab
import numpy as np
### SURFACE '''
x,y = np.meshgrid(np.linspace(-2.5,2), np.linspace(-2,2))
f = lambda x,y: .4*np.sin(2*np.pi*x)*np.sin(2*np.pi*y)
z=f(x,y)
mlab.surf(x.T,y.T,z.T, colormap="copper")
### SPHERES '''
px,py = np.meshgrid(np.arange(-2,2)+.25, np.arange(-2,2)+.75)
px,py = px.flatten(),py.flatten()
pz = np.ones_like(px)*0.05
r = np.ones_like(px)*.4
mlab.points3d(px,py,pz,r, color=(0.9,0.05,.3), scale_factor=1)
mlab.show()
You need to determine the minima of the function, which are (with your parametrization) at (x = integer + 0.25, y=integer + 0.75) or the other way round. Then you can simply parametrize the spheres using spherical coordinates (for example as done here: python matplotlib: drawing 3D sphere with circumferences) and plot the spheres.
Now comes some good news and some bad news:
1.) The good news is that the minima are correctly determined and that the spheres are created. In the below plot you can see that they are right above the blue parts of the surface plot (where the blue parts show indeed the minima).
2.) The bad news is that you will have a hard time looking for another angle where the spheres are actually correctly rendered. I do not know a solution to this rather annoying behaviour, therefore you will probably have to play around until you have found the right angle. Have fun!
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def func(x, y):
return np.sin(2*np.pi*x)*np.sin(2*np.pi*y) / 3
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = y = np.arange(-2.0, 2.0, 0.05)
# Get the minima of the function.
minsx1 = np.arange(int(np.amin(x)) + 0.25, int(np.amax(x)) + 0.25 + 1, 1)
minsy1 = np.arange(int(np.amin(y)) + 0.75, int(np.amax(y)) + 0.75 + 1, 1)
minsx2 = np.arange(int(np.amin(x)) + 0.75, int(np.amax(x)) + 0.75 + 1, 1)
minsy2 = np.arange(int(np.amin(y)) + 0.25, int(np.amax(y)) + 0.25 + 1, 1)
X, Y = np.meshgrid(x, y)
zs = np.array([func(x,y) for x,y in zip(np.ravel(X), np.ravel(Y))])
Z = zs.reshape(X.shape)
# Color map for better detection of minima (blue)
ax.plot_surface(X, Y, Z, cmap="viridis")
ax.set_zlim3d(-1,1)
# Spherical coordinates
r = 0.15
phi = np.linspace(0, 2 * np.pi, 30)
theta = np.linspace(0, np.pi, 30)
# Write spherical coordinates in cartesian coordinates.
x = r * np.outer(np.cos(phi), np.sin(theta))
y = r * np.outer(np.sin(phi), np.sin(theta))
z = r * np.outer(np.ones(np.size(phi)), np.cos(theta))
# Plot the spheres.
for xp in minsx1:
for yp in minsy1:
sphere = ax.plot_surface(x+xp, y+yp, z+0.35, color='r')
for xp in minsx2:
for yp in minsy2:
sphere = ax.plot_surface(x+xp, y+yp, z+0.35, color='r')
ax.view_init(elev=90, azim=0)
plt.savefig('test.png')
plt.show()

no points appearring in 2d histogram

I have been trying to input data from arrays into a 2d histogram and use plt.imshow to show it. However I have been unsuccessful so far. I get an empty array with the correct labels but there are no points to be detected. I have looked up examples online, to no avail.
d[0]= array([ 559.31299349, 507.44063212, 596.05952403, ..., 531.48861237,
525.03097371, 512.51860453])
d[1]= array([ 604.44753343, 513.26418859, 658.79946406, ..., 543.09749822,
522.69953756, 579.40805154])
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
d = np.load('XandY.npy')
x = d[0]
y = d[1]
gridx = np.linspace(min(x),max(x),10)
gridy = np.linspace(min(y),max(y),10)
H, xedges, yedges = np.histogram2d(x, y, bins=[gridx, gridy])
fig1 = plt.figure()
plt.plot=(x,y,'ro')
plt.grid(True)
plt.xlabel('array X')
plt.ylabel('array y')
plt.figure()
myextent =[xedges[0],xedges[-1],yedges[0],yedges[-1]]
plt.imshow(H.T,origin='low',extent=myextent,aspect='auto')
plt.plot(x,y,'ro')
plt.colorbar()
plt.show()
Where have my points gone?
The following simplified code worked for me.
def main():
#output image
outpath=os.path.join('data', 'matplot_hist2d_example.png')
#get 100 random scatter points in the range(500.0-700.0)
np.random.seed(1702)
rand_pts=np.random.uniform(low=500.0, high=700.0, size=(100,2))
x = rand_pts[:, 0]
y = rand_pts[:, 1]
#ensure 10 bins along each axis
gridx = np.linspace(min(x), max(x), 11)
gridy = np.linspace(min(y), max(y), 11)
#histogram 2d
H, xedges, yedges = np.histogram2d(x, y, bins=[gridx, gridy])
#plotting
fig1 = plt.figure()
plt.xlabel('array X')
plt.ylabel('array Y')
myextent =[xedges[0],xedges[-1],yedges[0],yedges[-1]]
plt.imshow(H.T, origin='low', extent=myextent,aspect='auto')
plt.colorbar()
#show points as well
plt.scatter(x,y)
plt.show()
#save
fig1.savefig(outpath)
plt.close(fig1)
pass
See the results below

Plotting vertical cylindrical surfaces

Provided we have a contour on the xy plane, how can we plot "a curtain" raised from the contour to the limiting surface?
An example:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
def figure():
fig = plt.figure(figsize=(8,6))
axes = fig.gca(projection='3d')
x = np.linspace(-2, 2, 100)
y = np.linspace(-2, 2, 100)
x, y = np.meshgrid(x, y)
t1 = np.linspace(0, 8/9, 100)
x1 = t1
y1 = (2*t1)**0.5
f1 = lambda x, y: y
plt.plot(x1, y1)
axes.plot_surface(x, y, f1(x, y),color ='red', alpha=0.1)
axes.set_xlim(-2,2)
axes.set_ylim(-2,2)
figure()
How to plot a surface from the given line to the limiting surface?
Somebody wanted help plotting an intersection here cylinder "cuts" a sphere in python you could use the vertical cylinder part. It uses u, v parameters to generate x, y, z values

Categories