热图半球图

Heat Map half-sphere plot

我想绘制 720 x 180 的 theta 和 phi 值 theta 范围 =(-180 到 180,步长为 0.5) phi 范围 =(0 到 -90,步长为 0.5)

这是我拥有的数据集示例:

Theta Phi Values
-180   0    0.2
-180   0.5  0.5
...    ...  ...
-180   -90  1.1
-179.5  0   0.92
...    ...  ...
 0     -90   0.6
...    ...  ...
180   -89.5 0.17
180   -90   0.12

所以最终,我想得到一个类似这样的情节:

我知道如何使用下面的代码创建半球体,但如何从我的数据框中分配值?

import matplotlib.pyplot as plt
from matplotlib import cm, colors
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

# Create a sphere
r = 2
pi = np.pi
cos = np.cos
sin = np.sin
altitude
phi, theta = np.mgrid[0.0:0.5*pi:180j, 0.0:2.0*pi:720j] # phi = alti, theta = azi
x = r*sin(phi)*cos(theta)
y = r*sin(phi)*sin(theta)
z = r*cos(phi)    
#Set colours and render
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(
    x, y, z,  rstride=4, cstride=4, color='w', alpha=0.1, linewidth=0)    
ax.set_xlim([-2.2,2.2])
ax.set_ylim([-2.2,2.2])
ax.set_zlim([0,3])
ax.set_aspect("equal")
ax.plot_wireframe(x, y, z, color="k")

代码生成这个

Axes3D.plot_surface 接受二维数组作为输入。它提供 facecolors 参数,该参数接受与输入数组形状相同的数组。这个数组应该有每张脸的颜色作为其中的 rgba 元组。因此,可以将数组值标准化为最大 1 的范围,并为其提供来自 matplotlib.cm 的颜色图。

剩下的问题就是从提供的 3 列列表中获取这个数组。给定一个长度为 n*m 的数据表,其中第一列表示 x 值,第二列表示 y 值,第三列表示某个值,排序首先按 x 然后通过 y。然后可以将最后一列重塑为 (n,m) 数组,其中 nx 值的数量和 m y 值的数量,使用 .reshape((m,n)).T.

一些进一步的评论:

  1. 在下面的解决方案中,我需要模仿这个数组并直接使用辐射角度,而不是度数。
  2. 点数,180*720好像有点高。为了 window 不花很长时间轮换,我减少了那个数字。
  3. 我重命名了角度,使它们与通常的教科书定义相匹配,phi = 方位角,theta = 倾角(从 z 轴)。
  4. 使用plot_wireframe可能没有太大意义,因为它会隐藏下面的表面。如果需要线框,可以使用要绘制的点数和 linewidth 关键字参数。将 linewidth 设置为较大的值,例如 3 或 5 会使表面看起来不错,将其设置为 1 会留下一些线框外观。

这是完整的解决方案。

import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

#theta inclination angle
#phi azimuthal angle
n_theta = 50 # number of values for theta
n_phi = 200  # number of values for phi
r = 2        #radius of sphere

theta, phi = np.mgrid[0.0:0.5*np.pi:n_theta*1j, 0.0:2.0*np.pi:n_phi*1j]

x = r*np.sin(theta)*np.cos(phi)
y = r*np.sin(theta)*np.sin(phi)
z = r*np.cos(theta)

# mimic the input array
# array columns phi, theta, value
# first n_theta entries: phi=0, second n_theta entries: phi=0.0315..
inp = []
for j in phi[0,:]:
    for i in theta[:,0]:
        val = 0.7+np.cos(j)*np.sin(i+np.pi/4.)# put something useful here
        inp.append([j, i, val])
inp = np.array(inp)
print inp.shape
print inp[49:60, :]

#reshape the input array to the shape of the x,y,z arrays. 
c = inp[:,2].reshape((n_phi,n_theta)).T
print z.shape
print c.shape


#Set colours and render
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
#use facecolors argument, provide array of same shape as z
# cm.<cmapname>() allows to get rgba color from array.
# array must be normalized between 0 and 1
ax.plot_surface(
    x,y,z,  rstride=1, cstride=1, facecolors=cm.hot(c/c.max()), alpha=0.9, linewidth=1) 
ax.set_xlim([-2.2,2.2])
ax.set_ylim([-2.2,2.2])
ax.set_zlim([0,4.4])
ax.set_aspect("equal")
#ax.plot_wireframe(x, y, z, color="k") #not needed?!
plt.savefig(__file__+".png")
plt.show()