如何在轴对称3D曲面的截面上叠加2D流线图?
3D轴对称系统矢量场可视化方案
需求概述
- 针对3D轴对称球体系统,已在x-z平面求解得到矢量场并生成2D流线图
- 基于轴对称性,将2D解绕z轴旋转得到完整3D矢量场
- 期望可视化效果:绘制裁剪掉x>0且y<0区域的3D曲面,在裁剪后露出的两个平面(
y=0且x>0、x=0且y<0)上叠加原2D流线图 - 优先选择连续流线图:因矢量场结构复杂,相比离散箭头(quiver),流线图更易展现整体分布
实现步骤
1. 3D曲面裁剪
在生成球体上下部分的网格时,添加条件判断,将X>0且Y<0的网格点设为np.nan,从而去除该区域的曲面渲染。
2. 流线图的3D投影
- y=0且x>0平面:直接复用x-z平面的流线数据,将所有点的y坐标设为0,在3D坐标系中绘制流线
- x=0且y<0平面:利用轴对称性,将x-z平面中x≥0的流线数据进行坐标转换:x→-y,y→0,保持z不变,得到y-z平面(y≤0)的流线数据后绘制
3. 层级与样式控制
通过zorder参数将流线图置于曲面上方,确保流线清晰可见;保留原2D流线的色彩与密度设置,保证可视化一致性
完整可复现代码
import numpy as np import matplotlib import matplotlib.pyplot as plt from scipy.interpolate import griddata ell = 0.62 gamma = 1 Rbase, Rcap, center = 0.62, 0.62, 0 ################### ###### 预处理矢量场数据(生成x-z平面插值后的矢量场) res = 200 x_Car = [[-1.8417224772056704e-16, -0.0, -0.5726312223685197], [7.597102430294396e-17, 0.0, -0.6203504908994001], [0.020037100834806584, 0.0, -0.5857436781333181], [0.030439155856322415, 0.0, -0.6196032515649681], [0.020156894294067102, 0.0, -0.5477190352848064], [-1.6882456041048852e-16, -0.0, -0.5249119538377125]] m_Car = [[-1.60647705e-05, 0.00000000e+00, -2.43349475e-01], [ 0.00022923, 0. , -0.21359168], [ 0.00627664, 0. , -0.23712676], [ 0.01131077, 0. , -0.21533309], [ 0.00655443, 0. , -0.25987232], [ 2.65801174e-05, 0.00000000e+00, -2.72980539e-01]] m_Car_T, x_Car_T = np.array(m_Car).T, np.array(x_Car).T cm = matplotlib.cm.coolwarm norm = matplotlib.colors.Normalize(vmin=0,vmax=1) sm = matplotlib.cm.ScalarMappable(cmap=cm, norm=norm) xx, zz = x_Car_T[0], x_Car_T[2] x_grid, z_grid = np.meshgrid(np.linspace(xx.min(),xx.max(),res),np.linspace(zz.min(),zz.max(),res)) # 插值得到x-z平面的矢量场分量 x_vector_interp = griddata((xx, zz), m_Car_T[0], (x_grid, z_grid), method='cubic') z_vector_interp = griddata((xx, zz), m_Car_T[2], (x_grid, z_grid), method='cubic') ################### ###### 3D可视化:裁剪曲面 + 叠加流线图 width, height = matplotlib.figure.figaspect(1.2)*1.5 fig, ax = plt.subplots(1, 1, figsize=(width, height), subplot_kw={"projection": "3d"}) ### 绘制上半球(Cap)并裁剪x>0且y<0区域 theta, phi = np.mgrid[0:np.pi/2:180j, 0:1.5*np.pi:270j] X = Rcap*np.sin(theta)*np.cos(phi) Y = Rcap*np.sin(theta)*np.sin(phi) Z = Rcap*np.cos(theta)+center # 裁剪条件:x>0且y<0的区域设为nan mask = (X > 0) & (Y < 0) Z[mask] = np.nan ax.plot_surface(X/ell, Y/ell, Z/ell, linewidth=0, antialiased=False, rstride=1, cstride=1, color='grey') ### 绘制下半球(Base)并裁剪x>0且y<0区域 theta, phi = np.mgrid[np.pi/2:np.pi:180j, 0:1.5*np.pi:270j] X = Rbase*np.sin(theta)*np.cos(phi) Y = Rbase*np.sin(theta)*np.sin(phi) Z = Rbase*np.cos(theta) # 裁剪条件:x>0且y<0的区域设为nan mask = (X > 0) & (Y < 0) Z[mask] = np.nan ax.plot_surface(X/ell, Y/ell, Z/ell, linewidth=0, antialiased=False, rstride=1, cstride=1, color='gainsboro') ### 绘制中心轴 ax.plot([0,0],[0,0],[-Rbase/ell,(Rcap+center)/ell],'k-',zorder=100) ### 叠加y=0且x>0平面的流线图 # 提取x>0的网格区域 x_pos_mask = x_grid > 0 x_stream = x_grid[x_pos_mask]/ell z_stream = z_grid[x_pos_mask]/ell u_stream = x_vector_interp[x_pos_mask] v_stream = z_vector_interp[x_pos_mask] # 在3D中绘制流线,y坐标固定为0 ax.streamplot(x_stream, np.zeros_like(x_stream), z_stream, u_stream, np.zeros_like(u_stream), v_stream, color='k', density=1.1, zorder=200) ### 叠加x=0且y<0平面的流线图 # 利用轴对称性转换坐标:x→-y,y→0,z保持不变 # 提取x≥0的网格区域(避免重复) x_nonneg_mask = x_grid >= 0 # 转换坐标:原x变为-y(y<0),原y=0变为x=0 y_stream = -x_grid[x_nonneg_mask]/ell z_stream = z_grid[x_nonneg_mask]/ell # 矢量分量转换:原x分量变为-y分量,原z分量不变 u_stream = np.zeros_like(x_vector_interp[x_nonneg_mask]) v_stream = -x_vector_interp[x_nonneg_mask] w_stream = z_vector_interp[x_nonneg_mask] # 在3D中绘制流线,x坐标固定为0 ax.streamplot(np.zeros_like(y_stream), y_stream, z_stream, u_stream, v_stream, w_stream, color='k', density=1.1, zorder=200) ### 设置坐标轴标签与比例 ax.set_xlabel('$x/\ell$'); ax.set_ylabel('$y/\ell$'); ax.set_zlabel('$z/\ell$') ax.set_box_aspect([1,1,(2*Rbase)/(Rbase+Rcap-center)]) # 添加颜色条 fig.colorbar(sm, label=r'$|\mathbf{m}|$', pad=0.1) plt.show()
替代优化方案
如果需要更直观的3D流线展示,可直接将x-z平面的流线绕z轴旋转生成3D流线束:
- 取x-z平面的单条流线,生成多个角度的旋转副本,形成环绕z轴的流线管
- 配合曲面透明度调整,可同时展现内部矢量场分布与外部曲面形态
内容的提问来源于stack exchange,提问作者pamgur
相关产品推荐
相关产品推荐

