如何绘制相交的平面?
我想用matplotlib这个工具画一幅图,图里有两个相交的平面,透明度要合适,这样可以显示它们的相对方向。同时,图中还需要有两个平面上的圆和向量,都是以2D的方式展示出来。
我不太确定有没有现成的工具包可以做到这一点,有没有什么建议呢?
2 个回答
Matplotlib确实可以做3D投影,但在最终的2D图像中,虚线的宽度是固定的,看起来并不像是在倾斜的平面上铺展。如果几何形状简单,且“轨道”是圆形的,那可能还行,但如果你想画的是从某个角度看起来的椭圆,观众可能会希望能看到更多关于整个3D布局的视觉线索。
如果我想做一个很漂亮的插图,甚至更好更花哨,而且不需要自动化处理,我会先为每个平面创建图形——至少是虚线圆圈——作为简单的平面2D图像,使用手边的工具,比如像Illustrator或Inkscape这样的矢量绘图软件,或者如果有数据的话,也可以在matplotlib中制作。
然后,我会用POV-Ray或Blender来建模这些平面,随意设置角度,圆形的东西(比如行星)用球体来表示。之前生成的2D图形会作为纹理贴到这些平面上。POV-Ray使用一种脚本语言,可以记录、修改和复制,以便将来使用。如果只是一次性的,我不介意手动操作,Blender也是个不错的选择。无论用哪个工具,最终的结果都是将3D几何元素投影到2D图像中。
那些圆形的东西,我称之为“行星”,在最终作品中应该是平面圆圈吗?如果是这样,我会在渲染出的3D图像上用矢量绘图软件来绘制它们。但我猜你可能更喜欢3D的球体。
展示的样本没有光照或阴影。阴影可以帮助更清晰地理解3D中的几何形状,虽然前面的插图还不错。短短的绿色线条显示了倾斜平面上的行星在红线上的位置,看起来还算清楚,但加上阴影会更好。第二幅插图在形状、位置和各个元素的交点上看起来有点混乱,这里阴影会更有帮助。POV-Ray或Blender可以轻松地创建这些效果。更进一步,互相反射的效果,称为辐射度,可以帮助在2D图像中看到3D关系。现在做这种高级效果很简单,不需要光学或图形方面的专业知识,只要知道它的存在即可。
当然,这些建议对那些已经熟悉3D图形和POV-Ray等工具的人才有用。
如果想要一个自动化的解决方案,使用OpenGL在某个快速简单的程序中可能是最好的选择。不过,阴影可能需要一些额外的工作。
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')
dim = 10
X, Y = np.meshgrid([-dim, dim], [-dim, dim])
Z = np.zeros((2, 2))
angle = .5
X2, Y2 = np.meshgrid([-dim, dim], [0, dim])
Z2 = Y2 * angle
X3, Y3 = np.meshgrid([-dim, dim], [-dim, 0])
Z3 = Y3 * angle
r = 7
M = 1000
th = np.linspace(0, 2 * np.pi, M)
x, y, z = r * np.cos(th), r * np.sin(th), angle * r * np.sin(th)
ax.plot_surface(X2, Y3, Z3, color='blue', alpha=.5, linewidth=0, zorder=-1)
ax.plot(x[y < 0], y[y < 0], z[y < 0], lw=5, linestyle='--', color='green',
zorder=0)
ax.plot_surface(X, Y, Z, color='red', alpha=.5, linewidth=0, zorder=1)
ax.plot(r * np.sin(th), r * np.cos(th), np.zeros(M), lw=5, linestyle='--',
color='k', zorder=2)
ax.plot_surface(X2, Y2, Z2, color='blue', alpha=.5, linewidth=0, zorder=3)
ax.plot(x[y > 0], y[y > 0], z[y > 0], lw=5, linestyle='--', color='green',
zorder=4)
plt.axis('off')
plt.show()
注意事项:
我使用的版本和当前的主版本非常接近,所以我不确定旧版本能否正常工作。
分开绘制图形的原因是,'上面'和'下面'的判断方式有点复杂(我不太确定
zorder
是否真的有用),而且这实际上取决于绘制顺序。因此,表面不能相交(一个表面在任何地方都在另一个表面之上),所以你需要分别绘制交点两侧的部分。(你可以看到我没有分开的黑线,看起来像是在上面的蓝色平面上)。表面的'正确'排序似乎也依赖于视角。