2 回答
TA贡献1934条经验 获得超2个赞
这是建立在 Andrea 的出色答案的基础上的,其中添加了一些对点之间可能具有相当宽间距的真实世界数据有所帮助的补充。当我第一次以 45 度间距绘制一些东西时,它看起来像这样:
有两个明显的问题:
这些面非常大,只有一种颜色,尽管它们跨越了很宽的数值范围。
形状关于原点对称,但面的颜色不对称。
可以通过对数据进行线性插值来改进问题 1,以便将每个面分为多个可以具有不同颜色的部分。
问题 2 发生的原因是面部颜色的分配方式。想象一下 2D 平面上的 3x3 点网格,每个点都有一个值。当您绘制曲面时,将只有 2x2 个面,因此最后一行和最后一列的值被丢弃,每个面的颜色仅由面的一个角决定。我们真正想要的是每个面中心的值。我们可以通过取四个角值的平均值并使用它来分配颜色来估计这一点。
在计算上,这最终类似于问题 1 的插值,因此我对两者使用了相同的函数“interp_array”。我不是一个 Python 程序员,所以可能有一种更有效的方法来做到这一点,但它可以完成工作。
这是修复了问题 2 但没有插值的图。对称性是固定的,但只使用了 2 种颜色,因为面与原点等距。
这是在点之间进行 8x 插值的最终图。现在它更接近于您在商业天线测量软件中看到的那种连续彩色图。
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as Axes3D
from matplotlib import cm, colors
def interp_array(N1): # add interpolated rows and columns to array
N2 = np.empty([int(N1.shape[0]), int(2*N1.shape[1] - 1)]) # insert interpolated columns
N2[:, 0] = N1[:, 0] # original column
for k in range(N1.shape[1] - 1): # loop through columns
N2[:, 2*k+1] = np.mean(N1[:, [k, k + 1]], axis=1) # interpolated column
N2[:, 2*k+2] = N1[:, k+1] # original column
N3 = np.empty([int(2*N2.shape[0]-1), int(N2.shape[1])]) # insert interpolated columns
N3[0] = N2[0] # original row
for k in range(N2.shape[0] - 1): # loop through rows
N3[2*k+1] = np.mean(N2[[k, k + 1]], axis=0) # interpolated row
N3[2*k+2] = N2[k+1] # original row
return N3
vals_theta = np.arange(0,181,45)
vals_phi = np.arange(0,361,45)
vals_phi, vals_theta = np.meshgrid(vals_phi, vals_theta)
THETA = np.deg2rad(vals_theta)
PHI = np.deg2rad(vals_phi)
# simulate the power data
R = abs(np.cos(PHI)*np.sin(THETA)) # 2 lobes (front and back)
interp_factor = 3 # 0 = no interpolation, 1 = 2x the points, 2 = 4x the points, 3 = 8x, etc
X = R * np.sin(THETA) * np.cos(PHI)
Y = R * np.sin(THETA) * np.sin(PHI)
Z = R * np.cos(THETA)
for counter in range(interp_factor): # Interpolate between points to increase number of faces
X = interp_array(X)
Y = interp_array(Y)
Z = interp_array(Z)
fig = plt.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
ax.grid(True)
ax.axis('on')
ax.set_xticks([])
ax.set_yticks([])
ax.set_zticks([])
N = np.sqrt(X**2 + Y**2 + Z**2)
Rmax = np.max(N)
N = N/Rmax
axes_length = 1.5
ax.plot([0, axes_length*Rmax], [0, 0], [0, 0], linewidth=2, color='red')
ax.plot([0, 0], [0, axes_length*Rmax], [0, 0], linewidth=2, color='green')
ax.plot([0, 0], [0, 0], [0, axes_length*Rmax], linewidth=2, color='blue')
# Find middle points between values for face colours
N = interp_array(N)[1::2,1::2]
mycol = cm.jet(N)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=mycol, linewidth=0.5, antialiased=True, shade=False) # , alpha=0.5, zorder = 0.5)
ax.set_xlim([-axes_length*Rmax, axes_length*Rmax])
ax.set_ylim([-axes_length*Rmax, axes_length*Rmax])
ax.set_zlim([-axes_length*Rmax, axes_length*Rmax])
m = cm.ScalarMappable(cmap=cm.jet)
m.set_array(R)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
fig.colorbar(m, shrink=0.8)
ax.view_init(azim=300, elev=30)
plt.show()
TA贡献1946条经验 获得超3个赞
您可以添加单位长度的轴线:
ax.plot([0, 1], [0, 0], [0, 0], linewidth=2, color = 'red')
ax.plot([0, 0], [0, 1], [0, 0], linewidth=2, color = 'green')
ax.plot([0, 0], [0, 0], [0, 1], linewidth=2, color = 'blue')
关于表面的颜色,您需要定义一个表达式来表示距原点的距离,然后使用此表达式创建您的颜色图并将其传递给facecolors参数ax.plot_surfaceas 此处:
dist = np.sqrt(X**2 + Y**2 + Z**2)
dist_max = np.max(dist)
my_col = cm.jet(dist/dist_max)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=my_col, linewidth=0, antialiased=False)
完整代码:
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = 8*np.sin(R)
dist = np.sqrt(X**2 + Y**2 + Z**2)
dist_max = np.max(dist)
my_col = cm.jet(dist/dist_max)
axes_length = 1.5
ax.plot([0, axes_length*dist_max], [0, 0], [0, 0], linewidth=2, color = 'red')
ax.plot([0, 0], [0, axes_length*dist_max], [0, 0], linewidth=2, color = 'green')
ax.plot([0, 0], [0, 0], [0, axes_length*dist_max], linewidth=2, color = 'blue')
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=my_col,
linewidth=0, antialiased=False)
ax.set_xlim([-axes_length*dist_max, axes_length*dist_max])
ax.set_ylim([-axes_length*dist_max, axes_length*dist_max])
ax.set_zlim([-axes_length*dist_max, axes_length*dist_max])
plt.show()
这给了我这个结果:
如您所见,表面的颜色从原点附近的蓝色变为远离原点的红色。将此代码应用于您的数据应该不难。
添加回答
举报