I am having problems with matplotlibs 3dplot. If I plot two 3d objects, the one that is supposed to be in front is sometimes in the back. Take for example the following code
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as pl
import numpy as np
fig = pl.figure()
ax = fig.add_subplot(111, projection='3d')
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
X = 10 * np.outer(np.cos(u), np.sin(v))
Y = 10 * np.outer(np.sin(u), np.sin(v))
Z = 10 * np.outer(np.ones(np.size(u)), np.cos(v))
ax.plot_surface(X+10,Y,Z, rstride=4, cstride=4, color='b')
u=np.linspace(-2,2,100)
X = 10 * np.outer(np.ones(len(u)), u)
Y = 10 * np.outer(u, np.ones(len(u)))
Z = 10 * np.zeros((len(u), len(u)))
ax.plot_surface(Z,X,Y, rstride=4, cstride=4, color='b')
pl.show()
It is supposed to plot a plane, with a sphere in from of it, but the sphere appears to be behind the plane.
Related
I have 4 arrays x, y, z and T of length n and I want to plot a 3D curve using matplotlib. The (x, y, z) are the points positions and T is the value of each point (which is plotted as color), like the temperature of each point. How can I do it?
Example code:
import numpy as np
from matplotlib import pyplot as plt
fig = plt.figure()
ax = fig.gca(projection='3d')
n = 100
cmap = plt.get_cmap("bwr")
theta = np.linspace(-4 * np.pi, 4 * np.pi, n)
z = np.linspace(-2, 2, n)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
T = (2*np.random.rand(n) - 1) # All the values are in [-1, 1]
What I found over the internet:
It's possible to use cmap with scatter like shown in the docs and in this stackoverflow question
ax = plt.gca()
ax.scatter(x, y, z, cmap=cmap, c=T)
The problem is that scatter is a set of points, not a curve.
In this stackoverflow question the solution was divide in n-1 intervals and each interval we use a different color like
t = (T - np.min(T))/(np.max(T)-np.min(T)) # Normalize
for i in range(n-1):
plt.plot(x[i:i+2], y[i:i+2], z[i:i+2], c=cmap(t[i])
The problem is that each segment has only one color, but it should be an gradient. The last value is not even used.
Useful links:
Matplotlib - Colormaps
Matplotlib - Tutorial 3D
This is a case where you probably need to use Line3DCollection. This is the recipe:
create segments from your array of coordinates.
create a Line3DCollection object.
add that collection to the axis.
set the axis limits.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Line3DCollection
from matplotlib.cm import ScalarMappable
from matplotlib.colors import Normalize
def get_segments(x, y, z):
"""Convert lists of coordinates to a list of segments to be used
with Matplotlib's Line3DCollection.
"""
points = np.ma.array((x, y, z)).T.reshape(-1, 1, 3)
return np.ma.concatenate([points[:-1], points[1:]], axis=1)
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
n = 100
cmap = plt.get_cmap("bwr")
theta = np.linspace(-4 * np.pi, 4 * np.pi, n)
z = np.linspace(-2, 2, n)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
T = np.cos(theta)
segments = get_segments(x, y, z)
c = Line3DCollection(segments, cmap=cmap, array=T)
ax.add_collection(c)
fig.colorbar(c)
ax.set_xlim(x.min(), x.max())
ax.set_ylim(y.min(), y.max())
ax.set_zlim(z.min(), z.max())
plt.show()
I am trying to plot the following function on a unit sphere, the points should be on the sphere and fill up the whole sphere however some of the points are falling off. Any suggestions why? I believe it is because the sphere is not spanning 1,1,1 3D grid but I am not sure how to edit my code to fix this.
from itertools import product, combinations
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
def d(kx,ky):
M = 1
B = 1
vf = 1
kxx,kyy = np.meshgrid(kx,ky)
x = (vf*kxx)/(np.sqrt(((((vf**2)*(kxx**2)))+((vf**2)*(kyy**2))+(M-B*(kxx**2+(kyy**2)))**2)))
y = (vf*kxx)/(np.sqrt(((((vf**2)*(kxx**2)))+((vf**2)*(kyy**2))+(M-B*(kxx**2+(kyy**2)))**2)))
z = (M-B*(kxx**2+(kyy**2)))/(np.sqrt(((((vf**2)*(kxx**2)))+((vf**2)*(kyy**2))+(M-B*(kxx**2+(kyy**2)))**2)))
return x,y,z
kx = np.linspace(-2, 2, 10)
ky = np.linspace(-2, 2, 10)
xi, yi, zi = d(kx,ky)
phi = np.linspace(0, np.pi, 100)
theta = np.linspace(0, 2*np.pi, 100)
phi, theta = np.meshgrid(phi, theta)
x = np.sin(phi) * np.cos(theta)
y = np.sin(phi) * np.sin(theta)
z = np.cos(phi)
fig = plt.figure(figsize=plt.figaspect(1.))
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x, y, z, color="w", rstride=1, cstride=1)
ax.scatter(xi,yi,zi,color="k",s=20)
plt.show()
Thank you kindly,
How can one plot a spherical segment, specifically a sphere "slice" in Python?
I know how to plot a sphere surface via
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = 10 * np.outer(np.cos(u), np.sin(v))
y = 10 * np.outer(np.sin(u), np.sin(v))
z = 10 * np.outer(np.ones(np.size(u)), np.cos(v))
ax.plot_surface(x, y, z, rstride=4, cstride=4, color='b')
plt.show()
or some variation of that code, but I'm struggeling to plot only a part of the sphere, leading to an image like the following:
https://en.wikipedia.org/wiki/Spherical_segment#/media/File:LaoHaiKugelschicht1.png
If I vary the code I presented above by manipulating the definitions of u and v, e.g.:
u = np.linspace(0, 2 * np.pi, 20)
v = np.linspace(0, np.pi, 20)
the sphere is still presented as a whole, but with a very poor resolution.
Changing the starting point of the linspace range doens't seem to change anything.
I have figured out something that works for me. Here you go:
q = 0.5 # defines upper starting point of the spherical segment
p = 0.8 # defines ending point of the spherical segment as ratio
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(q, p * np.pi, p * 100)
x = r * np.outer(np.cos(u), np.sin(v)) + x_0
y = r * np.outer(np.sin(u), np.sin(v)) + y_0
z = r * np.outer(np.ones(np.size(u)), np.cos(v)) + z_0
ax.plot_surface(x, y, z, color='b')
I would like to draw a sphere with points on its surface using Matplotlib. These points shall be connected by a spiral that spirals from one side of the sphere to the other.
To clarify this a little bit the plot should more or less look like this:
Has anyone a tip about how to do this?
Need to know parameters of spiral, formula or set of points.
However I post a code to plot a line with markers on a sphere for your start:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_aspect('equal')
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = 1 * np.outer(np.cos(u), np.sin(v))
y = 1 * np.outer(np.sin(u), np.sin(v))
z = 1 * np.outer(np.ones(np.size(u)), np.cos(v))
elev = 10.
rot = 80. / 180. * np.pi
ax.plot_surface(x, y, z, rstride=1, cstride=1, color='y', linewidth=0, alpha=0.5)
# plot lines in spherical coordinates system
a = np.array([-np.sin(elev / 180 * np.pi), 0, np.cos(elev / 180 * np.pi)])
b = np.array([0, 1, 0])
b = b * np.cos(rot) + np.cross(a, b) * np.sin(rot) + a * np.dot(a, b) * (1 - np.cos(rot))
ax.plot(np.sin(u),np.cos(u),0,color='r', linestyle = '-', marker='o', linewidth=2.5)
ax.view_init(elev = elev, azim = 0)
plt.show()
I have an array with values (0.7, 0.4, 0.1) and I would like to plot the corresponding ellipsoid with this code:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = 0.7 * np.outer(np.cos(u), np.sin(v))
y = 0.4 * np.outer(np.sin(u), np.sin(v))
z = 0.1 * np.outer(np.ones(np.size(u)), np.cos(v))
ax.plot_surface(x, y, z, rstride=4, cstride=4, color='b')
plt.show()
When I plot the figure, it looks like a sphere more than the expected ellipsoid. I suppose the problem is setting the "correct" range for the axes.
How could I solve this "problem"?
You could set proper ranges with ax.set_xlim(), ax.set_ylim() and ax.set_zlim() methods.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = 0.7 * np.outer(np.cos(u), np.sin(v))
y = 0.4 * np.outer(np.sin(u), np.sin(v))
z = 0.1 * np.outer(np.ones(np.size(u)), np.cos(v))
ax.plot_surface(x, y, z, rstride=4, cstride=4, color='b')
ax.set_xlim([-0.5, 0.5])
ax.set_ylim([-0.5, 0.5])
ax.set_zlim([-0.5, 0.5])
plt.show()