如何绘制立方体的面?

时间:2013-09-17 15:13:20

标签: python colors matplotlib cube

我已经完成了一个可以在python上旋转的立方体,但现在我想为我设置颜色,以便在旋转时识别每个面部。以下代码:

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from itertools import product, combinations
from numpy import sin, cos

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect("auto")
ax.set_autoscale_on(True)


#dibujar cubo
r = [-10, 10]
for s, e in combinations(np.array(list(product(r,r,r))), 2):
    if np.sum(np.abs(s-e)) == r[1]-r[0]:
        ax.plot3D(*zip(s,e), color="b")


#dibujar punto
#ax.scatter([0],[0],[0],color="g",s=100)

d = [-2, 2]
theta = np.radians(45)
for s, e in combinations(np.array(list(product(d,d,d))), 2):
    if np.sum(np.abs(s-e)) == d[1]-d[0]:
        s_rotated = [s[0]*cos(theta)-s[1]*sin(theta),
                     s[0]*sin(theta)+s[1]*cos(theta),
                     s[2]]
        e_rotated = [e[0]*cos(theta)-e[1]*sin(theta),
                     e[0]*sin(theta)+e[1]*cos(theta),
                     e[2]]
        ax.plot3D(*zip(s_rotated,e_rotated), color="g")
plt.show()

所以我想画一个里面的立方体。 有帮助吗? 谢谢!

2 个答案:

答案 0 :(得分:1)

您可以使用补丁。

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from itertools import product, combinations
from numpy import sin, cos
from matplotlib.patches import Rectangle, Circle, PathPatch
import mpl_toolkits.mplot3d.art3d as art3d

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect("auto")
ax.set_autoscale_on(True)


r = [-10, 10]
for s, e in combinations(np.array(list(product(r,r,r))), 2):
    if np.sum(np.abs(s-e)) == r[1]-r[0]:
        ax.plot3D(*zip(s,e), color="b")

colors = ['b', 'g', 'r', 'c', 'm', 'y']
for i, (z, zdir) in enumerate(product([-2,2], ['x','y','z'])):
    side = Rectangle((-2, -2), 4, 4, facecolor=colors[i])
    ax.add_patch(side)
    art3d.pathpatch_2d_to_3d(side, z=z, zdir=zdir)


plt.show()

enter image description here

如果需要比x-y平面更一般地旋转,可以使用Poly3Dcollection。这只是绘制立方体的顶部和底部。您希望如何生成顶点将取决于您正在做什么的详细信息。

from mpl_toolkits.mplot3d import Axes3D, art3d
import matplotlib.pyplot as plt
import numpy as np
from itertools import product, combinations
from numpy import sin, cos


fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect("auto")
ax.set_autoscale_on(True)


r = [-10, 10]
for s, e in combinations(np.array(list(product(r,r,r))), 2):
    if np.sum(np.abs(s-e)) == r[1]-r[0]:
        ax.plot3D(*zip(s,e), color="b")


btm = np.array([[-2, -2, -2],
                [-2, 2, -2],
                [ 2, 2, -2],
                [2, -2,-2]])
top = np.array([[-2, -2, 2],
                [-2, 2, 2],
                [ 2, 2, 2],
                [2, -2,2]])
theta = np.radians(45) 
rot_mx = np.array([[cos(theta), sin(theta), 0],
                    [-sin(theta), cos(theta), 0],
                    [          0,          0, 1]])

btm = np.dot(btm, rot_mx)
side = art3d.Poly3DCollection([btm])
side.set_color('r')
ax.add_collection3d(side)

top = np.dot(top, rot_mx)
side = art3d.Poly3DCollection([top])
side.set_color('g')
ax.add_collection3d(side)


plt.show()

enter image description here

答案 1 :(得分:0)

由于以下原因,您难以实现的效果:

  • matplotlib 知道它是一个立方体,因此您需要计算平面中的颜色点。

  • Matplotlib 3D绘图是将3D数据投影到2D中,这在绘制直线和平面的交点时尤为明显: enter image description here 当线条在平面下方时看起来不像它,你可以通过设置透明度来避免这种情况,当线条下方的线条alpha更小。这意味着你需要根据旋转面向观察者的“前向”旋转来计算,这可以交互式地改变!

  • 在matplotlib 3d中无法绘制某些内容,对于2D,您可以使用plt.fill_between,但此功能不会扩展到3D。

虽然前两个问题理论上可以通过写出立方体的数学,定义平面和相对于观察者的可见性来解决,但最后我真的不知道你将如何解决。基本上你需要在两者之间写填充,这个函数用3D中的阴影多边形填充区域。

有了这个令人沮丧的前景,我可以建议一些替代方案,只需在每个面上添加一些对角线十字架,因为你已经检查了顶点是否在同一条边上,你只需要检查它们是否是对角线,绘图和颜色。< / p>

或转移到图形绘图工具,旨在做这种事情。如果您对乳胶有任何经验,那么试试tikz 3D plotting它将代码与非常漂亮的输出结合起来,尽管它有点像faf。

修改:以下是将crosses放入多维数据集的方式:

for循环中的if语句检查点se之间的距离。由于这样做的方式,它不会检查实际差异,而是检查两者之间有多少向量长度,这可以通过打印np.sum(np.abs(s-e))来检查,4返回812的长度和if。所以我们希望用两个向量分隔的那些,即我们在另一个elif np.sum(np.abs(s-e))== 2 * (d[1]-d[0]): s_rotated = [s[0]*cos(theta)-s[1]*sin(theta), s[0]*sin(theta)+s[1]*cos(theta), s[2]] e_rotated = [e[0]*cos(theta)-e[1]*sin(theta), e[0]*sin(theta)+e[1]*cos(theta), e[2]] ax.plot3D(*zip(s_rotated,e_rotated), color="r") 语句中添加

{{1}}

以红色绘制由两个矢量长度分隔的所有点 enter image description here

显然,您希望以不同的颜色绘制每个十字形,这对于当前形式的代码是不可能的。这是因为我们只检查点之间的长度,需要有一种方法来区分不同的点集。

我不确定这样做的最好方法因此会停在这里,在我看来,你需要停止只是运行所有点的组合并实际上正确地标记点。