我正在尝试在球体周围绘制一条丝带,但没有成功:(
结果应如下所示:。它基本上是球体表面的一部分,但只是带状部分。
我写的代码:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Funzione per convertire le coordinate sferiche in coordinate cartesiane
# Le coordinate sferiche ci permettono di rappresentare la sfera in modo più semplice
def sferiche_a_cartesiane(r, theta, phi): # r raggio che varia, theta è la colatitudine
x = r * np.sin(phi) * np.cos(theta)
y = r * np.sin(phi) * np.sin(theta)
z = r * np.cos(phi)
return x, y, z
# Genera le coordinate sferiche per la sfera usando un numpy array di x numeri equidistanti
theta_sfera = np.linspace(0, 2 * np.pi, 100)
phi_sfera = np.linspace(0, np.pi, 50)
theta_sfera, phi_sfera = np.meshgrid(theta_sfera, phi_sfera) # coordinate vere e proprie
# Imposta il raggio della sfera
raggio_sfera = 1.0
# Calcola le coordinate cartesiane dalla sferiche
x_sfera, y_sfera, z_sfera = sferiche_a_cartesiane(raggio_sfera, theta_sfera, phi_sfera)
# Crea la figura e gli assi 3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# Disegna la sfera
ax.plot_surface(x_sfera, y_sfera, z_sfera, color='r', alpha=0.1, edgecolors=None, zorder=0)
t = np.linspace(-1, 1, 1000) # t appartiene a [-1, 1]
# Genera la curva parametrica con raggio leggermente ingrandito. Si derivano dal fatto che la sfera ha eq. x**2 + y**2 + z**2 = 1
x_curva = 1.01 * ((1 - t**2)**0.5) * np.cos(10 * np.pi * t)
y_curva = 1.01 * ((1 - t**2)**0.5) * np.sin(10 * np.pi * t)
z_curva = 1 * t
# Ruota la curva parametrica attorno alla sfera
angolo_rotazione = np.pi / 4
x_rotato = x_curva * np.cos(angolo_rotazione) - y_curva * np.sin(angolo_rotazione)
y_rotato = x_curva * np.sin(angolo_rotazione) + y_curva * np.cos(angolo_rotazione)
z_rotato = z_curva
# Disegna la curva parametrica ruotata
ax.plot(x_rotato, y_rotato, z_rotato, 'y', linewidth=2, zorder=1)
# Imposta gli assi
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
# Mostra il grafico
plt.show()
有人可以帮助我吗?
我查看了您的代码,但我不知道如何强制它看起来像您提供的图像。但是,我能够使用下面所示的代码生成非常相似的图像。这主要基于“这个问题”,其中涵盖了生成和绘制这些三角形。此代码也非常适合更改功能区以包含更多或更少的循环,或者使其更薄或更厚,因此它应该适应您的需求。
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import numpy as np
def poltocart(r, theta, phi):
# Clamp theta so that our slices don't stick out weirdly near the poles
theta = max(min(theta, np.pi), 0)
x = r * np.sin(theta) * np.cos(phi)
y = r * np.sin(theta) * np.sin(phi)
z = r * np.cos(theta)
return x, y, z
def _main():
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# Based on the provided image it looks like goes around
# maybe 5 times?
turns = 5
# How tightly to quantize the ribbon (100 has visible artifacts)
phi_slices = 500
# How thick each slice is (large = fatter ribbon)
slice_thick = np.deg2rad(20)
# The list of triangles to draw
ribbon = []
# How many times around to go based on turns
max_phi = turns * 2 * np.pi
# Generate all values of phi so that we can iterate through in pairs
phi_values = list(np.linspace(-np.pi, max_phi, phi_slices, endpoint=True))
for i in range(1, phi_slices - 1):
# The previous slice (so that edges align)
phix_minus1 = phi_values[i - 1]
# The current slice
phix0 = phi_values[i]
# Top edge triangle
p1 = poltocart(1, np.pi * phix_minus1 / max_phi, phix_minus1)
p2 = poltocart(1, np.pi * phix0 / max_phi + slice_thick, phix_minus1)
p3 = poltocart(1, np.pi * phix0 / max_phi, phix0)
# Bottom edge triangle
p1r = poltocart(1, np.pi * phix0 / max_phi + slice_thick + np.pi / phi_slices, phix0)
p2r = poltocart(1, np.pi * phix0 / max_phi + slice_thick, phix_minus1) # same as top
p3r = poltocart(1, np.pi * phix0 / max_phi, phix0) # same as top
ribbon.append((p1, p2, p3))
ribbon.append((p1r, p2r, p3r))
p31 = Poly3DCollection(ribbon)
p31.set(color=(1, 0, 0, 0.25))
p31.set(ec=(1, 0, 0, 0.0))
ax.add_collection(p31)
ax.set_xlim([-1, 1])
ax.set_ylim([-1, 1])
ax.set_zlim([-1, 1])
ax.set_axis_off()
plt.show()
if __name__ == '__main__':
_main()
这是它生成的输出: