如何绘制两个无曲面衔接断层的正螺旋面?
解决Matplotlib螺旋面合并后的衔接断层问题
使用Matplotlib绘制两个正螺旋面,将它们合并为单个网格后,曲面之间出现了明显的衔接断层,同时表面颜色映射效果不佳。
效果表现:两个螺旋面衔接处存在明显的断裂缝隙,颜色过渡不自然。
原实现代码
import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt from matplotlib import cm # 补充原代码遗漏的颜色模块导入 u = np.linspace(-np.pi, np.pi, 200) v = np.linspace(np.pi, -np.pi, 200) theta = np.pi U, V = np.meshgrid(u, v) X = np.cos(theta)*np.sinh(V)*np.sin(U) + np.sin(theta)*np.cosh(V)*np.cos(U) Y = -np.cos(theta)*np.sinh(V)*np.cos(U) + np.sin(theta)*np.cosh(V)*np.sin(U) Z = U*np.cos(theta)+V*np.sin(theta) i = -1 for j in np.linspace(0,.8, 2): X = np.append(X, X[::i,:], axis = 0) Y = np.append(Y, Y[::i,:], axis = 0) Z = np.append(Z, Z[::i,:]+j, axis = 0) i *=-1 r_cols = (X**2 + Y**2) r_cols /= np.max(r_cols) r_cols = cm.jet(r_cols) fig, ax = plt.subplots(figsize=(5,5), subplot_kw={"projection": "3d"}) ax.plot_surface(X, Y, Z, vmin=Z.min() * 2, facecolors = r_cols, rstride = 1 , linewidth=0 ) ax.set(xticklabels=[], yticklabels=[], zticklabels=[]) ax.view_init(elev=5, azim=40, roll=0) plt.show() # 补充原代码未定义的变量初始化 num = 0 fig.savefig('file{}.png'.format(num)) num +=1
尝试过的调整方法
- 调整u的取值范围以衔接螺旋轴:
u = np.append(np.linspace(0, -np.pi, 200), np.linspace(-np.pi, np.pi, 200)) u = np.append(u,np.linspace(np.pi,0, 200))
- 修改堆叠方式与Z轴的添加逻辑:
invert = -1 revert = 1 for j in np.linspace(0,.8, 2): X = np.append(X, X[::invert,::revert], axis = 0) Y = np.append(Y, Y[::invert,::revert], axis = 0) Z = np.append(Z, Z[::invert,::revert]+j, axis = 0) invert *=-1 revert *=-1
问题根源与解决方法
问题原因
- 网格参数不连续:原代码直接反转已有曲面的行进行拼接,导致两个曲面的U参数范围是
[-pi, pi]和[pi, -pi],边界处U值不连续,plot_surface无法生成连续三角面,从而出现断层。 - 颜色映射逻辑冲突:基于合并后的X/Y计算颜色,反转后的曲面颜色方向与原曲面相反,导致衔接处颜色突变。
修正后的代码
import numpy as np import matplotlib.pyplot as plt from matplotlib import cm # 第一个螺旋面参数范围 u1 = np.linspace(-np.pi, np.pi, 200) v = np.linspace(np.pi, -np.pi, 200) theta = np.pi # 生成第一个螺旋面网格 U1, V = np.meshgrid(u1, v) X1 = np.cos(theta)*np.sinh(V)*np.sin(U1) + np.sin(theta)*np.cosh(V)*np.cos(U1) Y1 = -np.cos(theta)*np.sinh(V)*np.cos(U1) + np.sin(theta)*np.cosh(V)*np.sin(U1) Z1 = U1*np.cos(theta) + V*np.sin(theta) # 第二个螺旋面U参数延续第一个的范围,保证衔接连续 u2 = np.linspace(np.pi, 3*np.pi, 200) U2, V = np.meshgrid(u2, v) X2 = np.cos(theta)*np.sinh(V)*np.sin(U2) + np.sin(theta)*np.cosh(V)*np.cos(U2) Y2 = -np.cos(theta)*np.sinh(V)*np.cos(U2) + np.sin(theta)*np.cosh(V)*np.sin(U2) Z2 = U2*np.cos(theta) + V*np.sin(theta) + 0.8 # 保持原偏移量 # 合并连续网格 X = np.vstack([X1, X2]) Y = np.vstack([Y1, Y2]) Z = np.vstack([Z1, Z2]) # 计算平滑过渡的颜色映射 r_cols = (X**2 + Y**2) r_cols /= np.max(r_cols) r_cols = cm.jet(r_cols) fig, ax = plt.subplots(figsize=(5,5), subplot_kw={"projection": "3d"}) ax.plot_surface(X, Y, Z, facecolors=r_cols, rstride=1, linewidth=0, antialiased=True) ax.set(xticklabels=[], yticklabels=[], zticklabels=[]) ax.view_init(elev=5, azim=40, roll=0) plt.show() num = 0 fig.savefig('file{}.png'.format(num))
关键调整点
- 连续参数范围:第二个螺旋面的U参数从
pi延续到3pi,与第一个曲面的[-pi, pi]在pi处自然衔接,避免网格断裂。 - 独立生成曲面:不再复用反转后的原曲面数据,重新计算第二个曲面的所有坐标,保证网格方向一致。
- 平滑颜色过渡:基于合并后的完整网格计算颜色,确保衔接处颜色连续。
内容的提问来源于stack exchange,提问作者Matthew.MC
相关产品推荐
相关产品推荐

