如何在Matplotlib中绘制缠绕球面的丝带?
在Matplotlib中绘制球面缠绕丝带的问题
我尝试在Matplotlib中绘制缠绕球面的丝带,但未得到预期效果。预期效果为球面表面环绕的带状区域(类似螺旋缠绕的丝带覆盖球面部分区域),目前仅画出了一条螺旋曲线,无法形成带状面。
原代码
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # 球坐标转笛卡尔坐标函数 # 球坐标可更简便地表示球面 def sferiche_a_cartesiane(r, theta, phi): # r为半径,theta为余纬度 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 # 生成球面的球坐标,使用等间距numpy数组 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) # 生成网格坐标 # 设置球面半径 raggio_sfera = 1.0 # 将球坐标转换为笛卡尔坐标 x_sfera, y_sfera, z_sfera = sferiche_a_cartesiane(raggio_sfera, theta_sfera, phi_sfera) # 创建3D绘图的画布和坐标轴 fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # 绘制球面 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 ∈ [-1, 1] # 生成半径略大的参数曲线,基于球面方程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 # 绕球面旋转参数曲线 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 # 绘制旋转后的参数曲线 ax.plot(x_rotato, y_rotato, z_rotato, 'y', linewidth=2, zorder=1) # 设置坐标轴标签 ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Z') # 显示图形 plt.show()
当前问题
运行上述代码后,仅能看到一条黄色螺旋曲线,无法形成预期的带状曲面。
解决方案
要生成带状区域,需要构造一组平行的螺旋路径并将其转换为网格曲面。核心修改点如下:
- 定义丝带宽度参数,生成多个偏移角度的螺旋路径
- 将所有路径点组合成网格,使用
plot_surface绘制曲面 - 确保丝带的所有点都贴合球面
修改后的完整代码
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # 球坐标转笛卡尔坐标函数 def sferiche_a_cartesiane(r, theta, phi): 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 # 生成球面 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) raggio_sfera = 1.0 x_sfera, y_sfera, z_sfera = sferiche_a_cartesiane(raggio_sfera, theta_sfera, phi_sfera) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.plot_surface(x_sfera, y_sfera, z_sfera, color='r', alpha=0.1, edgecolors=None, zorder=0) # 丝带参数设置 t = np.linspace(-1, 1, 1000) num_strips = 20 # 丝带包含的平行曲线数量 ribbon_width = 0.15 # 丝带宽度(弧度) radius = 1.01 # 丝带略大于球面半径 # 生成丝带的网格参数 phi_ribbon = np.arccos(t) # 对应球面的余纬度 theta_base = 10 * np.pi * t # 基础螺旋角度 theta_offset = np.linspace(-ribbon_width/2, ribbon_width/2, num_strips) # 宽度方向的偏移 # 构造丝带的网格坐标 theta_grid, phi_grid = np.meshgrid(theta_base + theta_offset[:, np.newaxis], phi_ribbon) x_ribbon = radius * np.sin(phi_grid) * np.cos(theta_grid) y_ribbon = radius * np.sin(phi_grid) * np.sin(theta_grid) z_ribbon = radius * np.cos(phi_grid) # 旋转丝带 angolo_rotazione = np.pi / 4 x_rotato = x_ribbon * np.cos(angolo_rotazione) - y_ribbon * np.sin(angolo_rotazione) y_rotato = x_ribbon * np.sin(angolo_rotazione) + y_ribbon * np.cos(angolo_rotazione) z_rotato = z_ribbon # 绘制丝带曲面 ax.plot_surface(x_rotato, y_rotato, z_rotato, color='y', alpha=0.7, zorder=1) ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Z') plt.show()
代码说明
- 用
meshgrid生成了丝带的网格坐标,将单条曲线扩展为一组平行的螺旋路径 - 通过
theta_offset控制丝带的宽度,调整ribbon_width可以改变丝带的宽窄 - 用
plot_surface绘制丝带曲面,设置alpha参数保证球面和丝带都可见
内容的提问来源于stack exchange,提问作者ludovica
相关产品推荐
相关产品推荐

