I'm trying to plot this "F" vector function in R3. Together with the Sphere centered at origin of radius Pi/2.
I do not understand why my vectors and my sphere are not at the same position.
I do not understand mlab.axes "axes visibility", I just would like to display the usual x,y,z axes.
Sorry if it is obvious to some, but I went through the standard documentation, few examples and google searches for a few hours, and I'm still clueless.
My current Mayavi Result and Code:
import numpy as np
from mayavi import mlab
# Functions
def h(t):
return np.exp(-1/t) * (1/np.cos(t))
def F(x, y, z):
norm = np.linalg.norm([x, y, z])
h_norm = (h(norm)/norm)
return [x*h_norm, y*h_norm, z*h_norm]
# Vectors
x, y, z = np.meshgrid(np.arange(-2, 2, 0.5),
np.arange(-2, 2, 0.5),
np.arange(-2, 2, 0.5))
u, v, w = F(x, y, z)
src = mlab.pipeline.vector_field(u, v, w)
mlab.pipeline.vectors(src, mask_points=20, scale_factor=.5)
# Ball
dphi, dtheta = np.pi/250.0, np.pi/250.0
[phi, theta] = np.mgrid[0:2*np.pi:dphi,
0:np.pi:dtheta]
r = np.pi / 2
x2 = r*np.sin(theta)*np.cos(phi)
y2 = r*np.sin(theta)*np.sin(phi)
z2 = r*np.cos(theta)
s = mlab.mesh(x2, y2, z2)
#mlab.axes(x_axis_visibility=True, y_axis_visibility=True)
# View it all.
mlab.outline()
mlab.show()
Related
I'm in the process of graphing different color values based on their hue, lightness, and saturation as the xyz axis. It works pretty well with matplotlib, here's a pic.
But recently I saw an image of a graph on the internet that's cylinder based
I couldn't find any info on the internet about it, and it seems that matplotlib doesn't support making this kind of graph. Does anyone know of a way to plot scatter points on a cylinder graph in python?
In order to place points on the surface of a cylinder, you would have to parameterize the surface. This is one way:
import numpy as np
import matplotlib.pyplot as plt
def cylinder(R, z_min, z_max, theta_max, N):
z = np.random.uniform(z_min, z_max, N)
theta = np.random.uniform(0, theta_max, N)
x = R * np.cos(theta)
y = R * np.sin(theta)
return x, y, z
def dics(z, R_max, theta_max, N):
r = np.random.uniform(0, R_max, N)
theta = np.random.uniform(0, theta_max, N)
x = r * np.cos(theta)
y = r * np.sin(theta)
return x, y, z * np.ones_like(x)
def plane(theta, R_max, z_min, z_max, N):
r = np.random.uniform(0, R_max, N)
x = r * np.cos(theta)
y = r * np.sin(theta)
z = np.random.uniform(z_min, z_max, N)
return x, y, z
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection="3d")
N = 1000
z_min = -1
z_max = 1
R = 3
theta_max = 1.5 * np.pi
# points on the cylindrical surface
x_cyl, y_cyl, z_cyl = cylinder(R, z_min, z_max, theta_max, N)
ax.scatter(x_cyl, y_cyl, z_cyl)
# points on the top cap
x_top, y_top, z_top = dics(z_max, R, theta_max, N)
ax.scatter(x_top, y_top, z_top)
# points on the bottom cap
x_bottom, y_bottom, z_bottom = dics(z_min, R, theta_max, N)
ax.scatter(x_bottom, y_bottom, z_bottom)
# points on the first slice-wall
x1, y1, z1 = plane(0, R, z_min, z_max, N)
ax.scatter(x1, y1, z1)
# points on the second slice-wall
x2, y2, z2 = plane(theta_max, R, z_min, z_max, N)
ax.scatter(x2, y2, z2)
plt.show()
Then, you would have to modify the above functions to return the angle theta and the radius r, so that you can apply colors based on H, S, V, but that's left for you as an exercise :)
Edit: if you just want to plot scatter points into the volume of a sliced cylinder, you could modify the cylinder function in this way:
def cylinder(R, z_min, z_max, theta_max, N):
z = np.random.uniform(z_min, z_max, N)
theta = np.random.uniform(0, theta_max, N)
r = np.random.uniform(0, R, N)
x = r * np.cos(theta)
y = r * np.sin(theta)
return x, y, z
I'm trying to create a bottle as a revolution solid using MatplotLib. I've got this points:
Image of the coordinates
Which in terms of coordinates are:
coords = [(0.00823433249299356, 0.06230346394288128),
(0.04086905251958573, 0.0648935210878489),
(0.08386400112604843, 0.0648935210878489),
(0.11753474401062763, 0.06541153251684242),
(0.14239929260231693, 0.05712334965294601),
(0.19109236692770842, 0.05401528107898486),
(0.2278711783862488, 0.05142522393401722),
(0.24133947554008045, 0.04158300678314021)]
The polynomial (more or less accurate) is:
Lambda(x, -19493.7965633925*x**6 + 13024.3747084876*x**5 - 3228.16456296349*x**4 + 368.816080918066*x**3 - 20.500262217588*x**2 + 0.545840273670868*x + 0.0590464366057008)
Which I get by:
# Getting the polynomial:
z = np.polyfit(xdata, ydata, 6)
# Being xdata and ydata the 2 vector from the coordinates
x = sp.symbols('x', real=True)
P = sp.Lambda(x,sum((a*x**i for i,a in enumerate(z[::-1]))))
print(P)
The point describe the outline of the bottle (cast your imagination) being the bottle in the plane XY.
How can I get, from that curve, a solid of revolution that recreates a bottle?
My objective is to be able to rotate the generator curve and create a solid of revolution, what I've tried is:
# Create the polynomial
pol = sp.lambdify(x,P(x),"numpy")
# Create the matrix of points
X = np.linspace(xdata[0], xdata[-1], 50)
Y = pol(X)
X, Y = np.meshgrid(X, Y)
# As long as a bottle is no more than a big amount of small cylinders, my
# equation should be more or less like:
# Z = x**2 + y** -R**2
# So we create here the equation
Z = X**2 + Y**2 - (Y - 0.0115)**2
# We create the #D figure
fig = plt.figure()
ax = plt.axes(projection="3d")
# And we representate it
surf = ax.plot_surface(X, Y, Z)
# We change the labels
ax.set_xlabel('$x$')
ax.set_ylabel('$y$')
ax.set_zlabel('$z$')
# And show the figure
plt.show()
The problem is that what I get is no longer a bottle (and I think is because how I'm using the plot_surface (I don't get very well how to use it by reading the documentation).
What I got is:
Image of the plotting. First I thought that was a problem related to the zoom, but I changed it and the figure is the same
I'll reference unutbu's answer to a similar question.
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as axes3d
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection='3d')
# grab more points between your coordinates, say 100 points
u = np.linspace(0.00823433249299356, 0.24133947554008045, 100)
def polynomial(x):
return -19493.7965633925*x**6 + 13024.3747084876*x**5 - 3228.16456296349*x**4 + 368.816080918066*x**3 - 20.500262217588*x**2 + 0.545840273670868*x + 0.0590464366057008
v = np.linspace(0, 2*np.pi, 60)
U, V = np.meshgrid(u, v)
X = U
Y1 = polynomial(X)*np.cos(V)
Z1 = polynomial(X)*np.sin(V)
# Revolving around the axis
Y2 = 0*np.cos(V)
Z2 = 0*np.sin(V)
ax.plot_surface(X, Y1, Z1, alpha=0.3, color='red', rstride=6, cstride=12)
ax.plot_surface(X, Y2, Z2, alpha=0.3, color='blue', rstride=6, cstride=12)
# set the limits of the axes
ax.set_xlim3d(-0.3, 0.3)
ax.set_ylim3d(-0.3, 0.3)
ax.set_zlim3d(-0.3, 0.3)
plt.show()
I am trying to draw a spherical harmonics for my college project. The following formula I want to depict,
Y = cos(theta)
for that, I wrote this code
import numpy as np
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
def sph2cart(r, phi, tta):
''' r is from 0 to infinity '''
''' phi is from 0 to 2*pi '''
''' tta is from 0 to pi '''
x = r* np.sin(tta)* np.cos(phi)
y = r* np.sin(tta)* np.sin(phi)
z = r* np.cos(tta)
return x, y, z
# phi running from 0 to pi and tta from 0 to pi
phi = np.linspace(0, 2* np.pi, 25)
tta = np.linspace(0, np.pi, 25)
# meshgrid to generate points
phi, tta = np.meshgrid(phi, tta)
# THIS IS THE FUNCTION
Y = np.cos(tta)
# finally all things in cartesian co-ordinate system
# Note that "Y" is acting as "r"
x, y, z = sph2cart( Y, phi, tta)
# plotting :-
fig = plt.figure()
ax = fig.add_subplot( 111 , projection='3d')
ax.plot_surface(x, y, z, linewidth = 0.5, edgecolors = 'k')
And, get the sphere as a result. Which is not correct, because actual result is dumbbell like shape. See the second row of this image,
https://upload.wikimedia.org/wikipedia/commons/thumb/6/62/Spherical_Harmonics.png/1024px-Spherical_Harmonics.png
The picture in the Wikipedia article Spherical harmonics is obtained by using the absolute value of a spherical harmonic as the r coordinate, and then coloring the surface according to the sign of the harmonic. Here is an approximation.
x, y, z = sph2cart(np.abs(Y), phi, tta)
fig = plt.figure()
ax = fig.add_subplot( 111 , projection='3d')
from matplotlib import cm
ax.set_aspect('equal')
ax.plot_surface(x, y, z, linewidth = 0.5, facecolors = cm.jet(Y), edgecolors = 'k')
When you use Y itself as r, the two hemispheres (positive Y and negative Y) end up mapped onto the same half of the above surface.
The Y you are passing to the function needs to be an absolute value to make it r, else z = cos(theta)^2 is always positive. If r is to be the radius then this what you should be doing.
x, y, z = sph2cart(np.abs(Y), phi, tta)
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()
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