matplotlib 在3D曲面图上叠加2D河流图

u0sqgete  于 2023-06-06  发布在  其他
关注(0)|答案(1)|浏览(198)

我正在处理一个3D轴对称系统(为了简单起见,我在这里显示一个球体)。我可以在x-z平面上解决这个问题,找到一个像下面流图中那样的向量场:

考虑到问题的对称性,我可以绕z轴旋转这个解,以获得完整的3D向量场。现在,我想以某种方式制作这个解决方案的3D图。我能想到的最直接的方法是绘制一个没有x>0 && y<0区域的系统曲面图,像这样:

然后将先前的流图叠加在由表面的“切口”产生的(y=0 && x>0)和(x=0 && y<0)平面上。如何实现这一目标有何建议?或者是否有其他更好的方法来可视化3D结果?
下面是生成图形的MWC(使用的x_Car和m_Car只是一个示例):

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

###################
###### Stream plot

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_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')

width, height = matplotlib.figure.figaspect(1.5)*1.2
fig, ax = plt.subplots(1,1,figsize=(width,height))
    
ax.pcolormesh(x_grid/ell, z_grid/ell, np.sqrt(x_vector_interp**2+z_vector_interp**2), norm=norm, cmap=cm)
ax.streamplot(x_grid/ell, z_grid/ell, x_vector_interp, z_vector_interp, 
              color='k', density=1.1) #, maxlength=6, integration_direction='both'

xrange = np.linspace(0,Rbase,100)
ax.plot(xrange/ell,-np.sqrt(Rbase**2-xrange**2)/ell,'k')
zcap = np.sign(gamma)*Rcap+center
ax.plot(xrange/ell,(np.sign(gamma)*np.sqrt(Rcap**2-xrange**2)+center)/ell,'k')
ax.plot((0,0),(-Rbase/ell,zcap/ell),'k')

ax.set_ylabel('$z/\ell$'); ax.set_ylim(-(Rbase+0.1)/ell,(Rbase+0.1)/ell)
ax.set_xlabel('$x/\ell$'); ax.set_xlim(-0.1/ell,(Rbase+0.1)/ell)
plt.colorbar(sm,label=r'$|\mathbf{m}|$')
# plt.axis('off')
# plt.axis("image") 

plt.show()

###################
###### Surface plot

width, height = matplotlib.figure.figaspect(1.2)*1.5
fig, ax = plt.subplots(1, 1, figsize=(width, height), subplot_kw={"projection": "3d"})

### Plot the cap
theta, phi = np.mgrid[0:np.pi/2:180j, 0:1.5*np.pi:270j] # phi = alti, theta = azi
X = Rcap*np.sin(theta)*np.cos(phi)
Y = Rcap*np.sin(theta)*np.sin(phi)
Z = Rcap*np.cos(theta)+center
for i in range(len(theta)):
    for j in range(len(phi[0])):
        if Z[i,j] < 0:
            Z[i,j] = np.nan
        else:
            pass
ax.plot_surface(X/ell, Y/ell, Z/ell, linewidth=0, antialiased=False, rstride=1, cstride=1, color='grey')

### Plot the base
theta, phi = np.mgrid[np.pi/2:np.pi:180j, 0:1.5*np.pi:270j] # phi = alti, theta = azi
X = Rbase*np.sin(theta)*np.cos(phi)
Y = Rbase*np.sin(theta)*np.sin(phi)
Z = Rbase*np.cos(theta)
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)

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

plt.show()
ebdffaop

ebdffaop1#

为此,可以使用彩色曲面图来显示等高线,使用箭图来显示矢量。我不得不调整zorder才能让情节在彼此面前。这样做的缺点是,如果你有一个交互式的人物并围绕它旋转,那么分层效果就不再起作用了。

import numpy as np
import matplotlib.pyplot as plt

plt.close("all")

N = 20
theta = np.linspace(0, np.pi, N)
phi = np.linspace(0, 3*np.pi/2, N)
Theta, Phi = np.meshgrid(theta, phi)

X = np.sin(Theta)*np.cos(Phi)
Y = np.sin(Theta)*np.sin(Phi)
Z = np.cos(Theta)

r = np.linspace(0, 1, N)
theta = np.linspace(-np.pi/2, np.pi/2, N)
R_vector, Theta_vector= np.meshgrid(r, theta)

X_vector = R_vector*np.cos(Theta_vector)
Z_vector= R_vector*np.sin(Theta_vector)
Y_vector= np.zeros_like(X_vector)

U = X_vector+ 2*Z_vector
V = -Z_vector
W = np.zeros_like(U)

magnitudes = np.sqrt(U**2 + V**2 + W**2)

U /= 10*magnitudes.max()
V /= 10*magnitudes.max()
W /= 10*magnitudes.max()

fig, ax = plt.subplots(subplot_kw={"projection":"3d", "computed_zorder":False})
ax.plot_surface(X, Y, Z, color="gainsboro", zorder=1)
ax.plot_surface(X_vector, Y_vector, Z_vector, 
                facecolors=plt.cm.coolwarm(magnitudes), zorder=2)
ax.quiver(X_vector, Y_vector, Z_vector, U, V, W, color="k", 
          antialiased=True, lw=0.5)
ax.set_aspect("equal")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
fig.tight_layout()

相关问题