用圆周绘制3D球体

8

我正在尝试使用matplotlib绘制像这样的球体:

enter image description here

但我找不到在背面画虚线的方法,而且垂直圆周看起来有点奇怪。

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(12,12), dpi=300)
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))
#for i in range(2):
#    ax.plot_surface(x+random.randint(-5,5), y+random.randint(-5,5), z+random.randint(-5,5),  rstride=4, cstride=4, color='b', linewidth=0, alpha=0.5)

ax.plot_surface(x, y, z,  rstride=4, cstride=4, color='b', linewidth=0, alpha=0.5)
ax.plot(np.sin(theta),np.cos(u),0,color='k')
ax.plot([0]*100,np.sin(theta),np.cos(u),color='k')

enter image description here

1个回答

12
在您展示的例子中,我认为圆不能彼此垂直(例如一个是赤道,另一个通过北极和南极)。如果水平圆是赤道,则北极必须位于通过代表球体的黄色圆心垂直线上的某个位置。否则,赤道的右侧将看起来比左侧更高或更低。然而,表示极圆的椭圆只在黄色圆的顶部和底部穿过该中心线。因此,北极位于球体的顶部,这意味着我们必须从赤道正面看,这意味着它应该看起来像一条线,而不是一个椭圆。
下面是一些代码,可以重现类似于您发布的图形的内容:
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))
#for i in range(2):
#    ax.plot_surface(x+random.randint(-5,5), y+random.randint(-5,5), z+random.randint(-5,5),  rstride=4, cstride=4, color='b', linewidth=0, alpha=0.5)
elev = 10.0
rot = 80.0 / 180 * np.pi
ax.plot_surface(x, y, z,  rstride=4, cstride=4, color='b', linewidth=0, alpha=0.5)
#calculate vectors for "vertical" circle
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='k', linestyle = 'dashed')
horiz_front = np.linspace(0, np.pi, 100)
ax.plot(np.sin(horiz_front),np.cos(horiz_front),0,color='k')
vert_front = np.linspace(np.pi / 2, 3 * np.pi / 2, 100)
ax.plot(a[0] * np.sin(u) + b[0] * np.cos(u), b[1] * np.cos(u), a[2] * np.sin(u) + b[2] * np.cos(u),color='k', linestyle = 'dashed')
ax.plot(a[0] * np.sin(vert_front) + b[0] * np.cos(vert_front), b[1] * np.cos(vert_front), a[2] * np.sin(vert_front) + b[2] * np.cos(vert_front),color='k')

ax.view_init(elev = elev, azim = 0)


plt.show()

3d sphere


非常好!但是,我目前遇到了“NotImplementedError:Axes3D当前仅支持aspect参数'auto'。您传递了'equal'。”浮点数(1.0)也不起作用。有没有办法得到一个“球形”的球? - AstroFloyd
1
@AstroFloyd 这个功能预计将在下一个版本的 matplotlib(3.6.0)中添加:https://github.com/matplotlib/matplotlib/pull/23017 - Scott
@Scott 谢谢。我发现 ax.set_box_aspect([1,1,1]) 可以实现我的需求:使用相等的 x、y、z 比例,无扭曲。 - AstroFloyd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接