Curve overlay on a Surface Matplotlib - python

I am interested in plotting curves on surfaces of revolution and have done so, but the surface is over-layed over the curve, does anyone know how to do the opposite?
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def surface_of_rev(u,v):
f = v
x = f*np.cos(u)
y = f*np.sin(u)
z = np.exp(-v**2)
return x,y,z
U = np.linspace(0,2*pi,n)
V = np.linspace(0.,3,n)
U,V = np.meshgrid(U,V)
x,y,z = surface_of_rev(U,V)
# curve
a = 3
b = 1
T = np.linspace(0,3,100)
xx,yy,zz = surface_of_rev(a*T+b,2*T)
# plot
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
curve = ax.plot(xx, yy, zz, 'o-', lw=2)
surface = ax.plot_surface(x, y, z,color= 'g')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
ax.view_init(50, 10)
plt.show()
Thank you

Related

Matplotlib smoothing 3D surface data

I have an issue with smoothing out the mesh representation of my 3D surface with matplotlib. Below, please see my example. I am having a hard time figuring out how to make the plot look nicer/smoother if possible. Thank you for your time in advance!
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import LightSource
import numpy as np
X = [1,1,1,1,1,1,50,50,50,50,50,50]
Y = [3,5,7,8,9,10,3,5,7,8,9,10]
Z = [5.23,3.11,17.54,0.93,40.11,10.15,1.47,14.32,5.46,55.93,40.8,10.2]
x = np.reshape(X, (2, 6))
y = np.reshape(Y, (2, 6))
z = np.reshape(Z, (2, 6))
X, Y = np.meshgrid(x, y)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x, y, z)
ax.set_xlabel('Persistence Length')
ax.set_ylabel('Complexity')
ax.set_zlabel('Relative number of configurational states')
surf = ax.plot_surface(x, y, z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
To obtain smooth line/surface you can set antialiased=True on the surface plot. Note that you were plotting two identical surface: in the following example I have eliminated the first.
To obtain a smoother mesh, you probably want to interpolate between your data points. One way to do that is to use griddata from the scipy.interpolate module.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from scipy.interpolate import griddata
X = [1,1,1,1,1,1,50,50,50,50,50,50]
Y = [3,5,7,8,9,10,3,5,7,8,9,10]
Z = [5.23,3.11,17.54,0.93,40.11,10.15,1.47,14.32,5.46,55.93,40.8,10.2]
points = np.array([X, Y]).T
# create a grid of coordinates between the minimum and
# maximum of your X and Y. 50j indicates 50 discretization
# points between the minimum and maximum.
X_grid, Y_grid = np.mgrid[1:50:50j, 3:10:50j]
# interpolate your values on the grid defined above
Z_grid = griddata(points, Z, (X_grid, Y_grid), method='cubic')
fig = plt.figure(constrained_layout=True)
ax = fig.add_subplot(111, projection='3d')
ax.set_xlabel('Persistence Length')
ax.set_ylabel('Complexity')
ax.set_zlabel('Relative number of configurational states')
surf = ax.plot_surface(X_grid, Y_grid, Z_grid, cmap=cm.coolwarm,
linewidth=0, antialiased=True)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
Here is an example of antialiased=False on the left, vs antialiased=True on the right:

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 do I create a colormap plot that can make a sphere in matplotlib 3d look like half i bright (look like the earth is illuminated on one side)

I am trying to create a 3D sphere in matplotlib and have it color like one side of the sphere is illuminated by the sun.
I have tried using matplotlib colormaps.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_axis_off()
phi = np.linspace(0,2*np.pi, 50)
theta = np.linspace(0, np.pi, 25)
x=np.outer(np.cos(phi), np.sin(theta))
y=np.outer(np.sin(phi), np.sin(theta))
z=np.outer(np.ones(np.size(phi)), np.cos(theta))
PHI=np.outer(phi,np.ones(np.size(theta)))
THETA=np.outer(np.ones(np.size(phi)),theta)
data = PHI/np.pi
norm = plt.Normalize(vmin=data.min(), vmax=data.max())
surface=ax.plot_surface(x, y, z, cstride=1, rstride=1,
facecolors=cm.jet(norm(data)))
surface=ax.plot_surface(x, y, z, cstride=1, rstride=1,
facecolors=cm.binary(norm(data)),cmap=plt.get_cmap('jet'))
plt.show()
I am expecting a sphere that looks something like this:
Or basically something that looks like the earth with the day side and the night side
But instead my results are something like this:
current plot from the above code
You need to use LightSource package:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.colors import LightSource
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_axis_off()
phi = np.linspace(0,2*np.pi, 100)
theta = np.linspace(0, np.pi, 50)
x=np.outer(np.cos(phi), np.sin(theta))
y=np.outer(np.sin(phi), np.sin(theta))
z=np.outer(np.ones(np.size(phi)), np.cos(theta))
PHI=np.outer(phi,np.ones(np.size(theta)))
THETA=np.outer(np.ones(np.size(phi)),theta)
data = PHI/np.pi
norm = plt.Normalize(vmin=data.min(), vmax=data.max())
# use Light Source
ls = LightSource(0, 0)
# create rgb shade
rgb = ls.shade(x, cmap=cm.Wistia, vert_exag=0.1, blend_mode='soft')
# blend shade
bsl = ls.blend_hsv(rgb, np.expand_dims(x*0.8, 2))
# plot surface
surface = ax.plot_surface(x, y, z, cstride=1, rstride=1, facecolors=bsl,
linewidth=0, antialiased=False, shade=False)
plt.show()
Output:

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!

Animating the motion of a particle in 3D in Python

I have 3xN array positions that vary in time for a particle. I want to take the coordinates at each time point, plot that position as a point on a 3D axis and then repeat, creating an animation.
I can create a single image of this effect using matplotlib's Axes3D
x_a = particle_a[:,0]
y_a = particle_a[:,1]
z_a = particle_a[:,2]
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(x_a, y_a, z_a, c='b')
plt.show
'particle_a' is just an array of shape (N,3) where N is the number of timepoints.
How can I animate this?
Adapting this example from the matplotlib site you can represent a particle moving in 3D with:
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation
def make_helix(n):
theta_max = 8 * np.pi
theta = np.linspace(0, theta_max, n)
x, y, z = theta, np.sin(theta), np.cos(theta)
helix = np.vstack((x, y, z))
return helix
def update_lines(num, dataLines, lines) :
for line, data in zip(lines, dataLines) :
line.set_data(data[0:2, num-1:num])
line.set_3d_properties(data[2,num-1:num])
return lines
# Attach 3D axis to the figure
fig = plt.figure()
ax = p3.Axes3D(fig)
n = 100
data = [make_helix(n)]
lines = [ax.plot(data[0][0,0:1], data[0][1,0:1], data[0][2,0:1], 'o')[0]]
# Setthe axes properties
ax.set_xlim3d([0.0, 8*np.pi])
ax.set_xlabel('X')
ax.set_ylim3d([-1.0, 1.0])
ax.set_ylabel('Y')
ax.set_zlim3d([-1.0, 1.0])
ax.set_zlabel('Z')
ax.set_title('3D Test')
# Creating the Animation object
ani = animation.FuncAnimation(fig, update_lines, n, fargs=(data, lines),
interval=50, blit=False)
plt.show()
(replace helix with your own data and set the axes limits accordingly).

Categories

Resources