plotting 3d equation in pyhton using matplotlib - python

I am trying to plot a 3d equation in python, but I am facing a type error: only size-1 array can be converted into scalars. The equation is:
$$z=f(x,y)=\cos(x)\cdot\cos(y)\cdot e^{(\frac{-\sqrt{(x^{2}+y^{2})}}{4})}$$
My Code is:
import numpy as np
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d.axes3d import Axes3D
import math
def f(x,y):
return math.cos(x)*math.cos(y)*math.e**(-math.sqrt(x**2 + y**2)/4)
x_5 = np.linspace(start=-2, stop=2, num=200)
y_5 = np.linspace(start=-2, stop=2, num=200)
x_5, y_5 = np.meshgrid(x_5, y_5)
#plotting
fig = plt.figure(figsize=(16, 15))
ax = fig.add_subplot(111, projection="3d")
ax.set_xlabel("X", fontsize=18)
ax.set_ylabel("Y", fontsize=18)
ax.set_zlabel("z=f(X,Y), Cost Function", fontsize=18)
ax.plot_surface(x_5, y_5, f(x_5,y_5), cmap=cm.coolwarm, alpha=0.5)
plt.show()

You need to use numpy functions, because math library can't handle arrays.
def f(x, y):
return np.cos(x) * np.cos(y) * np.exp(-np.sqrt(x**2 + y**2) / 4)

Related

Passing matplotlib objects to functions

I've wrote some functions to draw circles in the space, using matplotlib. Basically, I pass a 3D Axes object into the function, compute some data, and call the plot method. HereĀ“s my code:
import numpy as np
from numpy import sin, cos
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
t = np.linspace(0, 2*np.pi, 50)
def plot_circ(axes, color='black', alpha=0.8, **kwargs):
"""
Parameters
----------
axes : mpl_toolkits.mplot3d.axes3D.Axes3D
Where the sphere is plot.
**kwargs :
Arguments forwarded to "plot" method.
Returns
-------
None.
"""
x = cos(t) # Data to draw the circle
y = sin(t)
z = np.zeros(t.size)
axes.plot(x, y, z, color, alpha, **kwargs)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_box_aspect((1,1,1))
plot_circ(ax)
plt.show()
I get the following error when executing:
in plot_circ
axes.plot(x_hor, y_hor, z_hor, color, alpha, **kwargs)
in set_3d_properties
zs = np.broadcast_to(zs, xs.shape)
ValueError: operands could not be broadcast together with remapped shapes [original->remapped]: (50,) and requested shape (1,)
Now, if I remove the function and type everything directly, the code works:
import numpy as np
from numpy import sin, cos
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
t = np.linspace(0, 2*np.pi, 50)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_box_aspect((1,1,1))
x = cos(t)
y = sin(t)
z = np.zeros(t.size)
ax.plot(x, y, z, color='black', alpha=0.8)
plt.show()
I've read the error log, and it seems to be related with np.broadcast_to, and makes no sense since x and z have the same shape.
Thanks.

python - how do I fix interpolate grid origin issues in matplotlib?

I have a data set with a small sample size of data. For example:
My code looks something like this:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.interpolate import Rbf
df=pd.read_csv('test.csv')
df.head()
extent = x_extent = x_min, x_max, y_min, y_max = [df["X"].min()-1000, df["X"].max()+1000, df["Y"].min()-1000, df["Y"].min()+1000]
grid_x, grid_y = np.mgrid[x_min:x_max:100, y_min:y_max:100]
rbfi=Rbf(df["X"], df["Y"], df["Total"])
di=rbfi(grid_x, grid_y)
plt.scatter(grid_x, grid_y, s=10)
plt.figure(figsize=(15,15))
plt.imshow(di.T, origin="lower", extent=extent)
c2 = plt.scatter(df["X"], df["Y"], s=60, c=df["Total"], edgecolor='#ffffff66')
plt.colorbar(c2, shrink=0.6)
plt.show()
the result:
The result is a scatter plot of my points that appear to be in the correct place, but the interpolated grid is not covering the scatter points. So I think this has something to do with my origin not being correct, but I don't know how to fix this.
Two approaches here, one with a Delaunay triangulation, the other using the Radial Basis Function. Snippet and figure below.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.tri import Triangulation
from scipy.interpolate import Rbf
rng = np.random.default_rng()
X = rng.random(size=(15))
Y = rng.random(size=(15))
Total = rng.random(size=(15))
fig, (ax, bx) = plt.subplots(nrows=1, ncols=2, num=0, figsize=(16, 8))
tri = Triangulation(X, Y)
tctrf = ax.tricontourf(tri, Total)
gridY, gridX = np.mgrid[np.amin(Y):np.amax(Y):100 * 1j,
np.amin(X):np.amax(X):100 * 1j]
rbfi = Rbf(X, Y, Total, function='linear')
iTotal = rbfi(gridX, gridY)
bx.contourf(gridX, gridY, iTotal)
scat = ax.scatter(X, Y, s=60, c=Total, edgecolor='black')
fig.colorbar(scat, ax=ax)
scat = bx.scatter(X, Y, s=60, c=Total, edgecolor='black')
fig.colorbar(scat, ax=bx)
ax.set_aspect('equal')
bx.set_aspect('equal')
fig.tight_layout()
fig.savefig('so.png')
plt.show()

How to get the slice of a plot3d object?

I have some points and I plot the surface of them using the code below:
import matplotlib.pyplot as plt
from matplotlib import cm, colors
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# Create a sphere
r = 1
pi = np.pi
cos = np.cos
sin = np.sin
phi, theta = np.mgrid[0.0:pi:20j, 0.0:2.0*pi:20j]
radis=np.random.normal(1,0.2,(20,20))
x = radis*sin(phi)*cos(theta)
y = radis*sin(phi)*sin(theta)
z = radis*cos(phi)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(
x, y, z, rstride=1, cstride=1, color='c', alpha=0.3, linewidth=0)
ax.scatter3D(x,y,z, c='r')
ax.set_xlim([-1,1])
ax.set_ylim([-1,1])
ax.set_zlim([-1,1])
# ax.set_aspect("equal")
plt.tight_layout()
plt.show()
Then I get the 3d plot result:
The thing I want to do is that get the image of any plane, like z=0.
Is there any method or library can cover this problem?

How to do a 3D plot of gaussian using numpy?

I'm trying to plot a gaussian function using numpy.
the funtion is z=exp(-(x2+y2)/10) but I only get a 2D function
import numpy as np
from matplotlib import pyplot as plt
x=np.linspace(-10,10, num=100)
y=np.linspace(-10,10, num=100)
z=np.exp(-0.1*x**2-0.1*y**2)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_wireframe(x,y,z)
I obtain:
but I want to obtain:
I'm using numpy becouse I need the set of data.
You need to obtain the correct dimensions. This can be done using meshgrid. Also, your desired plot is a surface plot, not a wireframe (though you can do that too).
# import for colormaps
from matplotlib import cm
x=np.linspace(-10,10, num=100)
y=np.linspace(-10,10, num=100)
x, y = np.meshgrid(x, y)
z = np.exp(-0.1*x**2-0.1*y**2)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x,y,z, cmap=cm.jet)
plt.show()
given the original formula of a gaussian distribution I wrote the following code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D # <--- This is important for 3d plotting
A = 1
x0 = 0
y0 = 0
sigma_X = 2
sigma_Y = 2
xg = np.linspace(-5,5,num=100)
yg = np.linspace(-5,5,num=100)
theta= np.pi
X, Y = np.meshgrid(xg,yg)
a = np.cos(theta)**2/(2*sigma_X**2) + np.sin(theta)**2/(2*sigma_Y**2);
b = -np.sin(2*theta)/(4*sigma_X**2) + np.sin(2*theta)/(4*sigma_Y**2);
c = np.sin(theta)**2/(2*sigma_X**2) + np.cos(theta)**2/(2*sigma_Y**2);
aXXdet = np.array([a*(Xi-x0)**2 for Xi in X],float)
bbXYdet = np.array([2*b*(Xi-x0)*(Y[ii]-y0) for ii,Xi in enumerate(X)],float)
cYYdet = np.array([c*(Yi-y0)**2 for Yi in Y],float)
Z = np.array([A*np.exp( - (ai + bbXYdet[i] + cYYdet[i])) for i,ai in enumerate(aXXdet)],float);
# plot
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z, cmap=cm.coolwarm)
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')
plt.show()
which also plots the distribution. So you could play around with the parameters and see their effect!

matplotlib surface plot extends past axis limits

How do I make a nice paraboloid in Matplotlib that looks like
All I can get is this,
where the top is not "cut off". I've tried just dropping all values of the Z array outside of the radius of the parabola at the top, but that gives very jagged edges. Can someone help me?
Here is my code:
from matplotlib import *
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from pylab import *
import math
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X = np.arange(-5, 5, 0.1)
Y = np.arange(-5, 5, 0.1)
X, Y = np.meshgrid(X, Y)
Z = (X**2 + Y**2)
ax.set_zlim(-10, 20)
ax.plot_surface(X, Y, Z, alpha=0.9, rstride=4, cstride=4, linewidth=0.5, cmap=cm.summer)
plt.show()
For future reference, I had a thought to parametrize the surface in cylindrical coordinates, and it looks exactly how I want it:
from matplotlib import *
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from pylab import *
import math
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
r = T = np.arange(0, 2*pi, 0.01)
r, T = np.meshgrid(r, T)
#Parametrise it
X = r*np.cos(T)
Y = r*np.sin(T)
Z = r**2
ax.plot_surface(X, Y, Z, alpha=0.9, rstride=10, cstride=10, linewidth=0.5, cmap=cm.summer)
plt.show()
I guess it makes sense: when working with a cylindrical object, use cylindrical coordinates!
Manual data clipping
One approach I've seen that works is to manually clip the data; e.g. your example would be updated to
from matplotlib import *
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from pylab import *
import math
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X = np.arange(-5, 5, 0.1)
Y = np.arange(-5, 5, 0.1)
X, Y = np.meshgrid(X, Y)
Z = (X**2 + Y**2)
ax.set_zlim(-10, 20)
for i in range(len(X)):
for j in range(len(Y)):
if (Z[j,i] < -10) or (Z[j,i] > 20):
Z[j,i] = NaN
ax.plot_surface(X, Y, Z, alpha=0.9, rstride=4, cstride=4, linewidth=0.5, cmap=cm.summer)
plt.show()
Note
This can be done concisely for this case using
Z[Z>20] = NaN
Resulting in

Categories

Resources