Matplotlib 3d: surface does not cover a line - python

I draw a plane and a line crossing the plane.
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3
def plot_x_axis(ax):
x = np.array([-1, 1])
y = np.array([0, 0])
z = np.array([0, 0])
ax.plot(x, y, z, color='green')
def plot_yz_plane(ax):
a = np.array([0, 1, 0])
b = np.array([0, 0, 1])
U, V = np.meshgrid(np.linspace(-0.5, 0.5, 3), np.linspace(-0.5, 0.5, 3))
x = a[0] * U + b[0] * V
y = a[1] * U + b[1] * V
z = a[2] * U + b[2] * V
surf = ax.plot_surface(x, y, z, rstride=1, cstride=1, alpha=1.0, color='red')
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
plot_x_axis(ax)
plot_yz_plane(ax)
plt.show()
I expect that a part of this line (placed behind the plane) will be covered by the plane, but actually matplotlib shows all the objects as if the plane is transparent. How to fix this problem?

Related

How to create a line on a surface with "matplotlib" in python

I would like to draw two lines on a surface (the pink surface) to represent the two cutting lines of this pink surface and two 2d planes (x = y and x = -y), like the blue lines in the figure below. Does anyone know how to do it?
The code to generate the pink surface is as below:
import numpy as NP
import matplotlib.pyplot as PLT
def f(x1, x2):
return 0.5 * x1 + 0.6 * x2 + 0.2 * x1 * x1 + 0.1 * x1 * x2 + 0.3 * x2 * x2 + 4
x = NP.linspace(-3, 3, 100)
y = NP.linspace(-3, 3, 100)
xx, yy = NP.meshgrid(x,y)
z = f(xx, yy)
# set up the figure
fig = PLT.figure()
ax = fig.gca(projection='3d')
ax.set_xlim(-3, 3)
ax.set_ylim(3, -3)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
# plot the figure
ax.plot_surface(xx, yy, z, cmap="spring", alpha = 0.7)
# add the x=y line to the ground plane
ax.plot([-3, 3], [-3, 3], color = 'grey', linewidth = 1, linestyle='dashed')
# add the x=-y line to the ground plane
ax.plot([3, -3], [-3, 3], color = 'grey', linewidth = 1, linestyle='dashed')
PLT.show()
You can just use plot(x, -x, f(x, -x)) and plot(x, x, f(x, x)) to draw the curves. Note that matplotlib doesn't perfectly hide elements that are partially obscured by other elements.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot as plt
import numpy as np
def f(x1, x2):
return 0.5 * x1 + 0.6 * x2 + 0.2 * x1 * x1 + 0.1 * x1 * x2 + 0.3 * x2 * x2 + 4
x = np.linspace(-3, 3, 100)
y = np.linspace(-3, 3, 100)
xx, yy = np.meshgrid(x,y)
z = f(xx, yy)
# set up the figure
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_xlim(-3, 3)
ax.set_ylim(3, -3)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
# plot the figure
ax.plot_surface(xx, yy, z, cmap="spring", alpha = 0.7)
# add the x=y line to the ground plane
ax.plot([-3, 3], [-3, 3], color='grey', linewidth=1, linestyle='dashed')
# add the x=-y line to the ground plane
ax.plot([3, -3], [-3, 3], color='grey', linewidth=1, linestyle='dashed')
ax.plot(x, x, f(x, x), color='dodgerblue')
ax.plot(x, -x, f(x, -x), color='dodgerblue')
plt.show()

using matplot3d objects in 3d space with python, how can it correctly hide some part of object is further away?

I use matplot3d(ax.bar3d() and ax.plot) to plot two lines around a cuboid, when looking in bird viewbird view, this figure shows the read 3d relationship of all the objects. When looking from sideside view, some part of blue line that behind the green cylinder should be hidden, but this part still can be seen. I tried using parameter alpha, and it failed too. Does any body know how to deal with this ?
My matplotlib version is 2.1.0, and my python version is 3.4.7
# import
import matplotlib as mpl
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# global set
XMAX = 4
ZMAX = 15
mpl.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
print(mpl.__version__)
z = np.linspace(0, ZMAX, 5)
if True:
arrowstartt = np.zeros((3))
arrowstartx = np.zeros((3))
arrowstarty = np.zeros((3))
arrowendt = np.zeros((3))
arrowendx = np.zeros((3))
arrowendy = np.zeros((3))
arrowcolor= 'black'
fontsizes = 25
# x cors
x = (XMAX + 1) / np.max(z) * z
y = 0. * z
zz = 0. * z
ax.plot(x, y, zz, color=arrowcolor, linewidth=1)
arrowstartx[0] = x[-1]
arrowstarty[0] = y[-1]
arrowstartt[0] = zz[-1]
ax.text(x[-1], y[-1], zz[-1], "x", color='k', fontsize=fontsizes)
# y cors
x = 0. * z
y = 2 * XMAX / np.max(z) * z
zz = 0. * z
ax.plot(x, y, zz, color=arrowcolor, linewidth=1)
arrowstartx[1] = x[-1]
arrowstarty[1] = y[-1]
arrowstartt[1] = zz[-1]
ax.text(x[-1], y[-1], zz[-1]-1, "y", color='k', fontsize=fontsizes)
#z cor
x = 0. * z
y = 0. * z
zz = (XMAX) / np.max(z) * z
ax.plot(x, y, zz, color=arrowcolor, linewidth=1)
arrowstartx[2] = x[-1]
arrowstarty[2] = y[-1]
arrowstartt[2] = zz[-1]
ax.text(x[-1], y[-1], zz[-1], "z", color='k', fontsize=fontsizes)
# arrow end
arrowendx = arrowstartx + [1, 0, 0]
arrowendy = arrowstarty + [0, 1, 0]
arrowendt = arrowstartt + [0, 0, 1]
ax.quiver(arrowstartx, arrowstarty, arrowstartt, arrowendx, arrowendy, arrowendt,2, color=arrowcolor, linewidth=1)
# ax.set_xlabel('x')
# ax.set_ylabel('y')
# ax.set_zlabe('z')
# ax.arrow()
''' draw bar as a cylinder '''
if True:
# draw bar
xpos = 0.
ypos = 30.
dx = 1.4
dy = 2
ax.bar3d(xpos, ypos, 0, dx, dy, ZMAX, color='g', zsort='average')
#ax.bar3d(xpos, ypos, 0, dx, dy, ZMAX, alpha=0.8, color='g',zsort='average')
''' draw two lines'''
if True:
# the blue line
y = np.arange(0, 50, 1)
x = np.ones(len(y)) * (-2)
z = np.linspace(0, ZMAX, len(y))
ax.plot(x, y, z, 'b')
#ax.plot(x, y, z, 'b',alpha=0.8)
# the red line
y = np.arange(0, 50, 1)
x = np.ones(len(y)) * 2
z = np.linspace(0, ZMAX, len(y))
ax.plot(x, y, z, 'r')
plt.axis('off')
ax.legend()
plt.show()

How to close the ends of a cylinder in matplotlib

I am trying to make a 'closed' cylinder in matplotlib but I am not sure how to go about doing this. So far I have a cylinder with the ends open, the code for this is as follows:
#make a cylinder without the ends closed
import numpy as np
from matplotlib import cm
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from scipy.linalg import norm
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import numpy as np
import math
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
origin = [0,0,0]
#radius = R
p0 = np.array(origin)
p1 = np.array([8, 8, 8])
origin = np.array(origin)
R = 4
#vector in direction of axis
v = p1 - p0
#find magnitude of vector
mag = norm(v)
#unit vector in direction of axis
v = v / mag
#make some vector not in the same direction as v
not_v = np.array([1, 0, 0])
if (v == not_v).all():
not_v = np.array([0, 1, 0])
#make vector perpendicular to v
n1 = np.cross(v, not_v)
#normalize n1
n1 /= norm(n1)
#make unit vector perpendicular to v and n1
n2 = np.cross(v, n1)
#surface ranges over t from 0 to length of axis and 0 to 2*pi
t = np.linspace(0, mag, 600)
theta = np.linspace(0, 2 * np.pi, 100)
#use meshgrid to make 2d arrays
t, theta = np.meshgrid(t, theta)
#generate coordinates for surface
X, Y, Z = [p0[i] + v[i] * t + R * np.sin(theta) * n1[i] + R * np.cos(theta) * n2[i] for i in [0, 1, 2]]
#make the color for the faces
col1 = plt.cm.autumn(np.ones(600)) # linear gradient along the t-axis
col1 = np.repeat(col1[np.newaxis,:, :], 100, axis=0) # expand over the theta-axis
ax.plot_surface(X, Y,Z, facecolors = col1, shade = True,edgecolors = "None", alpha = 0.4, linewidth = 0)
plt.show()
Running this code produces the following image
How would I close the ends of the cylinder with a solid circle (i.e. disk)?
A quick and easy way that's similar to your other code is to generate a surface using strips from r=0 to r=R. Right before plt.show() add the following lines:
R = np.array([0,R])
# cap at t=0
X, Y, Z = [p0[i] + np.outer(R, np.sin(theta)) * n1[i] + np.outer(R, np.cos(theta))*n2[i] for i in [0, 1, 2]]
ax.plot_surface(X, Y, Z, edgecolors = "r", alpha=.4, linewidth = .1)
# cap at t=mag
X, Y, Z = [p0[i] + v[i]*mag + np.outer(R, np.sin(theta)) * n1[i] + np.outer(R, np.cos(theta))*n2[i] for i in [0, 1, 2]]
ax.plot_surface(X, Y, Z, edgecolors = "r", alpha=.4, linewidth = .1)
Here the colors are more for illustrative purposes, mostly so you can see the strips. The result looks like:

Facecolor changing edgecolor in matplotlib

I am trying to remove the edge color in the plot of a cylinder where I have set an alpha and facecolors. However, if I also set the facecolors, I can still see the edge colors. If I remove the alpha = 0.5 statement then the problem is resolved, however I need the alpha to be <1 . Here is an example:
You can still see the blue edgecolors even tough I have set the edgecolor to None.
This is the code where I use plot_surface()
ax.plot_surface(X, Y,Z, edgecolor = "None", facecolors = col1, alpha = 0.5)
Yet the edge colors are still there? However, if I remove the facecolors statement inside plot_surface() then the edge colors are no longer there. Here is the complete code:
import numpy as np
from matplotlib import cm
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from scipy.linalg import norm
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import random
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
origin = np.array([0, 0, 0])
#axis and radius
p0 = np.array([0, 0, 0])
p1 = np.array([8, 8, 8])
R = 4
#vector in direction of axis
v = p1 - p0
#find magnitude of vector
mag = norm(v)
#unit vector in direction of axis
v = v / mag
#make some vector not in the same direction as v
not_v = np.array([1, 0, 0])
if (v == not_v).all():
not_v = np.array([0, 1, 0])
#make vector perpendicular to v
n1 = np.cross(v, not_v)
#normalize n1
n1 /= norm(n1)
#make unit vector perpendicular to v and n1
n2 = np.cross(v, n1)
#surface ranges over t from 0 to length of axis and 0 to 2*pi
t = np.linspace(0, mag, 200)
theta = np.linspace(0, 2 * np.pi, 100)
#use meshgrid to make 2d arrays
t, theta = np.meshgrid(t, theta)
#generate coordinates for surface
X, Y, Z = [p0[i] + v[i] * t + R * np.sin(theta) * n1[i] + R * np.cos(theta) * n2[i] for i in [0, 1, 2]]
col1 = plt.cm.Blues(np.linspace(0,1,200)) # linear gradient along the t-axis
col1 = np.repeat(col1[np.newaxis,:, :], 100, axis=0) # expand over the theta- axis
ax.plot_surface(X, Y,Z, edgecolor = None, facecolors = col1, alpha = 0.5)
#plot axis
ax.plot(*zip(p0, p1), color = 'red')
ax.set_xlim(0, 10)
ax.set_ylim(0, 10)
ax.set_zlim(0, 10)
plt.axis('off')
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)
plt.show()
Setting linewidth=0 in plot_surface() solves this problem:
ax.plot_surface(X, Y, Z, edgecolor=None, facecolors=col1, alpha=0.5, linewidth=0)
p.s.: I didn't find this worth an answer, but per: Question with no answers, but issue solved in the comments (or extended in chat), I added it as a quick answer so the question can be marked as solved

matplotlib: add circle to plot

How do I add a small filled circle or point to a countour plot in matplotlib?
Here is an example, using pylab.Circle:
import numpy as np
import matplotlib.pyplot as plt
e = np.e
X, Y = np.meshgrid(np.linspace(0, 5, 100), np.linspace(0, 5, 100))
F = X ** Y
G = Y ** X
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
circ = plt.Circle((e, e), radius=0.07, color='g')
plt.contour(X, Y, (F - G), [0])
ax.add_patch(circ)
plt.show()
And here is another example (though not a contour plot) from the docs.
Or, you could just use plot:
import numpy as np
import matplotlib.pyplot as plt
e = np.e
X, Y = np.meshgrid(np.linspace(0, 5, 100), np.linspace(0, 5, 100))
F = X ** Y
G = Y ** X
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
plt.contour(X, Y, (F - G), [0])
plt.plot([e], [e], 'g.', markersize=20.0)
plt.show()

Categories

Resources