热力图半球形绘图

3

我希望将theta和phi的720 x 180个值绘制成图表,其中:

  • 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

最终,我希望得到一个类似于这样的图:

热力图[1] 我知道如何使用以下代码创建半球形,但是如何将来自我的数据框中的值分配给它呢?

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

这段代码生成了下面这个图像:

enter image description here

1个回答

3

Axes3D.plot_surface接受二维数组作为输入。它提供了facecolors参数,该参数接受与输入数组形状相同的数组。此数组应具有每个面的颜色作为rgba元组。因此,可以将数组值归一化为范围最高为1,并从matplotlib.cm中提供一个colormap。

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

一些进一步的说明:

  1. 在下面的解决方案中,我需要模拟此数组并直接使用弧度中的角度,而不是度数。
  2. 点数180*720似乎有点高。为了使窗口不需要花费很长时间才能旋转,我减少了该数字。
  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()

enter image description here


哇!这完全是我在寻找的。我一直在考虑对我的值进行归一化,并将其放入facecolors参数中,但在重新整形我的值时感到困惑。非常感谢@ImportanceOfBeingErnest! - Gerry Julian
@ImportanceOfBeingErnest 很好的回答,我对上面提到的类似类型的情节很感兴趣(除了我想要一个完整的球形表示)。您能否详细说明一下代码中“reshape”部分正在做什么?这部分“#将输入数组重塑为x,y,z数组的形状。 c = inp [:,2] .reshape((n_phi,n_theta)).T print z.shape print c.shape” - John Doe
1
c 必须是与 xyz 相同形状的数组。因此,位于 z[yi,xi] 的点的颜色需要是 c[yi,xi]。如何获取这取决于您拥有的数据,这里重新整形是一个简单的选项。 - ImportanceOfBeingErnest
@ImportanceOfBeingErnest 简短的问题,如果我的数据已经规范化(我的c值在0到1之间),那么在ax.plot_surface()函数中是否可以直接使用'c',而不是像您写的'(c/c.max())'呢?谢谢。 - John Doe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接