matplotlib 用单色描述第四维并通过线连接的4D图

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

过去几天我一直在网上搜索,没有看到任何解决方案。如果有人能看一下,我将不胜感激。
我试图绘制一个4D图,以显示在给定的经度、纬度和高度处的风向变化。
当物体从一个高度移动到另一个高度时,我在图表中看到了一个跳跃。可以用线把这些点连接起来吗?以指示这是运动。
示例代码如下所示:

import numpy as np
from matplotlib import pyplot as plt

lon = np.array([278.6695, 278.67,278.672265 ])
lat = np.array([48.476151, 48.472578621119, 48.45994295 ])
Z  = np.array([20000, 26502.51477,26501.65171])
distance = np.array([72.63856248, 70, 60 ])

fig = plt.figure(6)
ax = fig.add_subplot(111, projection='3d')
img = ax.scatter(lon, lat, Z, c=distance, cmap='inferno', alpha=1)
fig.colorbar(img)

ax.set_xlabel('longitude [Deg]')
ax.set_ylabel('latitude [Deg]')
ax.set_zlabel('Altitude [Km]')

plt.show()

绘制整个数据

的结果
其次,我想用一种颜色来显示距离(即黑色)而不是使用多种颜色。我的最终目标是有一个这样的情节

vuktfyat

vuktfyat1#

此答案显示如何创建您所要求的最终打印。这两种请求(单色和连接线)都是非常可能的。谷歌搜索你想要的情节图像显示,它最初是一个animation,这是我已经包括的其他东西。

回答

使用ax.plot(...)而不是ax.scatter(...),以便用直线连接这些点。然后,您可以添加一些其他功能,使输出看起来更像您的最终目标。

输出示例

这是一个数字显示了你的最终目标。下面添加了用于再现该图的代码。

还可以创建随时间推移的情节动画。注意,线的颜色随着距起始位置的距离增加而改变。此功能很容易被禁用。

代码

这是一些用于静态和动画图形的设置代码。

# necessary imports
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.art3d as art3d
from matplotlib.animation import FuncAnimation
from matplotlib.patches import Circle

# creating dummy data for two objects
lon = np.sort(277.0 + np.random.rand(2,100)*2)
lat = np.sort(48 + np.random.rand(2,100))
Z  = np.sort(20000 + np.random.rand(2,100)*8000)
lat[1] -= 2*(-lat[1][0] + lat[1]) # moving the lines in different directions

这是图的静态版本。

# creating the main figure and setting boundaries (change these as needed)
fig = plt.figure(6)
ax = fig.add_subplot(111, projection='3d')
ax.set_xlim(276, 280)
ax.set_ylim(46, 50)
ax.set_zlim(np.min(Z), 30000)

ax.set_xlabel('longitude [Deg]')
ax.set_ylabel('latitude [Deg]')
ax.set_zlabel('Altitude [Km]')
ax.zaxis.set_pane_color((0.36, 0.7, 0.42, 0.75)) # making the 'ground' green

# plotting data from object 1
# line plot for the path of the object
line = ax.plot(lon[0],lat[0],Z[0], c='k')
# plotting a vertical line from the ground to the final position of the object
vertLine = ax.plot([lon[0][-1],lon[0][-1]],[lat[0][-1],lat[0][-1]],[np.min(Z),Z[0][-1]], c='k')
# plotting a dot at the final postion of the object
dot = ax.plot(lon[0][-1], lat[0][-1], Z[0][-1], linestyle="", marker="o", c='k')

# plotting data from object 2 (see above for details)
line1 = ax.plot(lon[1],lat[1],Z[1], c='r', alpha=1)
vertLine1 = ax.plot([lon[1][-1],lon[1][-1]],[lat[1][-1],lat[1][-1]],[np.min(Z),Z[1][-1]], c='r', alpha=1)
dot1 = ax.plot(lon[1][-1], lat[1][-1], Z[1][-1], linestyle="", marker="o", c='r', alpha=1)

# adding green reference circle to the 'ground'
p = Circle((278,48.5),1, alpha=0.75, edgecolor=(0.3, 0.6, 0.39, 0.75), fill=False)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=np.min(Z), zdir="z")
ax.text(278,48.5,np.min(Z),"x", color=(0.3, 0.6, 0.39, 0.75))

# creating a new subplot for top down view
ax2 = fig.add_subplot(331)
ax2.set_xlim(276, 280)
ax2.set_ylim(46, 50)
ax2.set_aspect('equal')

# adding reference circle and background color
ax2.set_facecolor((0.36, 0.7, 0.42, 0.75))
p2 = Circle((278,48.5),1, alpha=0.75, facecolor=(0.3, 0.6, 0.39, 0.75))
ax2.add_patch(p2)

# plotting path lines and final position dots
ax2.plot(lon[0],lat[0], c='k')
ax2.plot(lon[1],lat[1], c='r')
ax2.scatter(lon[0][-1], lat[0][-1], c='k',s=20)
ax2.scatter(lon[1][-1], lat[1][-1], c='r',s=20)

# Show the plot!
plt.show()

这是一段时间内创建情节动画版本的代码。

# create figure/axis with appropriate params
fig = plt.figure(6)
ax = fig.add_subplot(111, projection='3d')
ax.set_xlim(276, 280)
ax.set_ylim(47, 50)
ax.set_zlim(18000, 30000)

ax.set_xlabel('longitude [Deg]')
ax.set_ylabel('latitude [Deg]')
ax.set_zlabel('Altitude [Km]')
ax.zaxis.set_pane_color((0.36, 0.7, 0.42, 0.75))

# create all components of the first object
line, = ax.plot(lon[0][:2],lat[0][:2],Z[0][:2], c='k', alpha=1)
vertLine, = ax.plot([lon[0][1],lon[0][1]],[lat[0][1],lat[0][1]],[np.min(Z[0]),Z[0][1]], c='k', alpha=1)
dot, = ax.plot(lon[0][1], lat[0][1], Z[0][1], linestyle="", marker="o", c='k', alpha=1)

# create all components of the second object
line1, = ax.plot(lon[1][:2],lat[1][:2],Z[1][:2], c='r', alpha=1)
vertLine1, = ax.plot([lon[1][1],lon[1][1]],[lat[1][1],lat[1][1]],[np.min(Z[1]),Z[1][1]], c='r', alpha=1)
dot1, = ax.plot(lon[1][1], lat[1][1], Z[1][1], linestyle="", marker="o", c='r', alpha=1)

def animate(i, colUpdate, numFrs): # colUpdate (bool), numFrs (int)
    # update the data for the path lines
    line.set_data(lon[0][:(i+1)*2],lat[0][:(i+1)*2])
    line.set_3d_properties(Z[0][:(i+1)*2])
    line1.set_data(lon[1][:(i+1)*2],lat[1][:(i+1)*2])
    line1.set_3d_properties(Z[1][:(i+1)*2])
    
    # update the data for the vertical lines
    vertLine.set_data(np.array([lon[0][((i+1)*2)-1],lon[0][((i+1)*2)-1]]),np.array([lat[0][((i+1)*2)-1],lat[0][((i+1)*2)-1]]))
    vertLine.set_3d_properties([np.min(Z[0]),Z[0][((i+1)*2)-1]])
    vertLine1.set_data(np.array([lon[1][((i+1)*2)-1],lon[1][((i+1)*2)-1]]),np.array([lat[1][((i+1)*2)-1],lat[1][((i+1)*2)-1]]))
    vertLine1.set_3d_properties([np.min(Z[1]),Z[1][((i+1)*2)-1]])
    
    # update the data for the endpoint dots
    dot.set_data(lon[0][((i+1)*2)-1],lat[0][((i+1)*2)-1])
    dot.set_3d_properties(Z[0][((i+1)*2)-1])
    dot1.set_data(lon[1][((i+1)*2)-1],lat[1][((i+1)*2)-1])
    dot1.set_3d_properties(Z[1][((i+1)*2)-1])

    # update the colors, if necessary
    if colUpdate:
        co = np.array([(i/numFrs),0.0,0.0])
        co1 = np.array([0.0,0.0,(i/numFrs)])
    
        line.set_color(co)
        vertLine.set_color(co)
        dot.set_color(co)
        
        line1.set_color(co1)
        vertLine1.set_color(co1)
        dot1.set_color(co1)
    # return all updated objects
    return line, vertLine, dot, line1, vertLine1, dot1,

# set params and create the animation artist
updateCol = True
numFrames = int(len(Z[0]) /2)
anim = FuncAnimation(fig, animate, frames = numFrames,interval = 100, fargs=(updateCol,numFrames,), blit=False, repeat=False)

# Show the plot!
plt.show()

编辑

为了修复代码的动画部分与Matplotlib 3.5.1兼容,必须更改animate(...)函数中的以下代码部分。替换以下内容:

# update the data for the endpoint dots
    dot.set_data(lon[0][((i+1)*2)-1],lat[0][((i+1)*2)-1])
    dot.set_3d_properties(Z[0][((i+1)*2)-1])
    dot1.set_data(lon[1][((i+1)*2)-1],lat[1][((i+1)*2)-1])
    dot1.set_3d_properties(Z[1][((i+1)*2)-1])

有:

# update the data for the endpoint dots
    dot.set_data(lon[0][((i+1)*2)-1],lat[0][((i+1)*2)-1])
    dot.set_3d_properties([Z[0][((i+1)*2)-1]])
    dot1.set_data(lon[1][((i+1)*2)-1],lat[1][((i+1)*2)-1])
    dot1.set_3d_properties([Z[1][((i+1)*2)-1]])

这只是将set_3d_properties(...)的输入更改为列表格式,这是Matplotlib 3.5.1中的新标准。有关问题的描述,请参阅此open issue
这样有用吗

相关问题