如何使用 MatPlotlib 在球体周围绘制丝带?

问题描述 投票:0回答:1

我正在尝试在球体周围绘制一条丝带,但没有成功:(

结果应如下所示:Ribbon around a sphere。它基本上是球体表面的一部分,但只是带状部分。

我写的代码:

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()

这是当前输出:Output

有人可以帮助我吗?

python matplotlib plot 3d calculus
1个回答
0
投票

我查看了您的代码,但我不知道如何强制它看起来像您提供的图像。但是,我能够使用下面所示的代码生成非常相似的图像。这主要基于“这个问题”,其中涵盖了生成和绘制这些三角形。此代码也非常适合更改功能区以包含更多或更少的循环,或者使其更薄或更厚,因此它应该适应您的需求。 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()

这是它生成的输出:

如果您有任何疑问,请告诉我。

© www.soinside.com 2019 - 2024. All rights reserved.