首页 > 解决方案 > 在 Python 中绘制 4D 数据热图

问题描述

嘿,我怎样才能在 3D 中绘制 2D 热图?现在我创建了一个 python 脚本来使用来自 CSV 的数据(CSV 格式:x、y、z、v)制作一个 2D 热图。例如:

第一个 csv

0,000;-110,000;110,000;0,101

第二个csv

0,000;-66,000;110,000;0,104

第三个csv

0,000;-22,000;110,000;0,119

……

在此示例中,它是 xz 平面中的热图,我创建了另外五个图,以便我可以在 3D 房间中插入六个 xz 平面图。在使用 matplotlib 的 4D 热图绘图中,有一个非常好的示例。但我不知道如何在我的情况下使用它。

import numpy as np
import os
import matplotlib.pyplot as plt
from scipy.interpolate import griddata


'Create a list for every parameter'
x = []
y = []
z = []
v = []

file_path = "path/."

'Insert data from csv into lists'
for root, dirs, files in os.walk(file_path, topdown=False):
   for name in files:
       if name[-4:] != '.csv': continue
       with open(os.path.join(root, name)) as data:
          data = np.genfromtxt((line.replace(',', '.') for line in data), delimiter=";")
          if data[1] == 22: 
            x.append(data[0])
            y.append(data[1])
            z.append(data[2])
            v.append(data[3])

'Create axis data'
xi = np.linspace(min(x), max(x), 1000)
zi = np.linspace(min(z), max(z), 1000)
vi = griddata((x, z), v, (xi[None,:], zi[:,None]), method='cubic')

'Create the contour plot'
CS = plt.contourf(xi, zi, vi, 20, cmap=plt.cm.rainbow)
plt.title("Heatmap xz-plane", y=1.05, 
          fontweight="bold")
plt.xlabel("length x in cm")
plt.xticks(np.arange(0, 201, step=40))
plt.ylabel("height z in cm")
plt.yticks(np.arange(110, 251, step=20))
cbar = plt.colorbar()
cbar.set_label("velocity v in m/s", labelpad=10)
plt.savefig('testplot.png', dpi=400)  
plt.show()

满足@keepAlive 的要求,希望看到他未经测试的答案的结果......:

它实际上很好用:-)

在此处输入图像描述

在此处输入图像描述

标签: python3d2dheatmap

解决方案


免责声明:我是引用示例的作者,所以我认为复制/粘贴自己并不是真正的问题。

请注意,您的数据集看起来(至少)不是 3 维的。但我会假设存在不情愿的选择偏差。

您首先需要汇总每个高度级别的“点”,我认为这是您的向量的第三个组成部分。一旦聚集,它们将构成你的位面。

# libraries
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import scipy.interpolate as si
from matplotlib import cm
import collections as co  # <------------------
import pandas as pd
import numpy as np

planes = co.defaultdict(list)

for root, dirs, files in os.walk(file_path, topdown=False):
   # [...]
       # [...]
       # [...]
          # [...]
          # [...]
            level = data[2]  # <------ third component.
            planes[level].append(data)

现在,在那个阶段,我们有一个数组列表level。让我们定义我们的grids_maker函数

def grids_maker(arrays_list, colnames=list('xyzg')):
    # 0- The idea behind `list('xyzg')` is only to change the order
    #    of names, not the names as such. In case for example you
    #    want to use another component than the third to organize
    #    your planes.
    # 1- Instantiate a dataframe so as to minimize the modification
    #    of the function copied/pasted pasted from
    #    https://stackoverflow.com/a/54075350/4194079
    # 2- Pandas is also going to do some other jobs for us, such as
    #    stacking arrays, etc....
    df = pd.DataFrame(arrays_list, columns=colnames)

    # Make things more legible
    xy = df.loc[:, ['x', 'y']]
    x  = xy.x
    y  = xy.y
    z  = df.z
    g  = df.g
    reso_x = reso_y = 50
    interp = 'cubic' # or 'nearest' or 'linear'

    # Convert the 4d-space's dimensions into grids
    grid_x, grid_y = np.mgrid[
        x.min():x.max():1j*reso_x,
        y.min():y.max():1j*reso_y
    ]

    grid_z = si.griddata(
        xy, z.values,
        (grid_x, grid_y),
        method=interp
    )

    grid_g = si.griddata(
        xy, g.values,
        (grid_x, grid_y),
        method=interp
    )

    return {
        'x' : grid_x,
        'y' : grid_y,
        'z' : grid_z,
        'g' : grid_g,
    }

让我们使用grids_maker我们的数组列表并获取每个 z 级别的第 4 维的极值。

g_mins = []
g_maxs = []
lgrids = {}

for level, arrays_list in planes.items():
    lgrids[level] = grids = grids_maker(arrays_list)
    g_mins.append(grids['g'].min())
    g_maxs.append(grids['g'].max())

让我们创建我们的(所有文件统一)色标并显示绘图。

# Create the 4th color-rendered dimension
scam = plt.cm.ScalarMappable(
    norm=cm.colors.Normalize(min(g_mins), max(g_maxs)),
    cmap='jet' # see https://matplotlib.org/examples/color/colormaps_reference.html
)
fig = plt.figure()
ax  = fig.gca(projection='3d')
for grids in lgrids.values(): 
    scam.set_array([])   
    ax.plot_surface(
        grids['x'], grids['y'], grids['z'],
        facecolors  = scam.to_rgba(grids['g']),
        antialiased = True,
        rstride=1, cstride=1, alpha=None
    )
plt.show()

我很高兴看到结果。


推荐阅读