求助:使用Matplotlib绘制带单元格的3D网格数据热力图
问题描述
我尝试将数据可视化为立方体,希望能绘制出立方体内部的每个单元格。目前生成的是未分割单元格的立方体,但需要实现类似3D热力图的效果,将预测结果可视化为带热力图的3D立方体。以下是我编写的代码:
%matplotlib notebook %matplotlib inline from mpl_toolkits.mplot3d import Axes3D matplotlib.rcParams['backend'] = "Qt4Agg" import numpy as np #each sell has its value y_pred = ([-3.4942558e+01, -1.0922590e+01, -9.4551229e+00, -2.6156654e+01, 1.1722648e+01, 6.4425749e-01, -1.1141028e+01, 5.9728470e+01, -4.5249408e-01, -8.7741699e+00, 9.9452820e+00, -2.8595707e+00, 2.6979692e+00, 7.9802217e+00, -1.1204488e+00, -4.5213123e+01, -7.1909481e-01, -8.4901733e+00, -9.2283611e+00, 5.0730385e+01, -7.9520082e-01, 1.4589276e+02, 8.4267479e+01, -6.7399621e+00, 2.1536992e+02, 5.0958019e+01, -7.7071385e+00, 8.4650040e+01, 2.5421507e+01, -4.1403370e+00, -8.5559702e+00, 5.5478176e+01, -1.0955868e+01, 3.1425345e+02, 1.9285686e+02, 4.6105843e+00, 6.6680554e+02, 2.7745572e+02, 1.2241451e+01, 5.1578967e+02, 1.8129390e+02, 7.3322144e+00, 1.2733205e+02, 4.4435711e+01, -2.0441423e-01, 8.3673248e+01, 1.7386259e+02, -1.6146477e-01, 5.9598431e+02, 5.7501422e+02, 4.7413929e+01, 7.6495886e+02, 6.5124884e+02, 7.9399048e+01, 4.0769174e+02, 3.2358469e+02, 3.6726327e+00, 7.5896362e+01, 9.8999245e+01, -1.7699455e+00, 1.0632815e+02, 2.3123619e+02, 4.5826878e+01, 3.6063211e+02, 5.6004309e+02, 1.3757048e+02, 3.7029037e+02, 5.5426331e+02, 1.0625824e+02, 1.7360068e+02, 2.6583237e+02, 2.0798336e+01, 4.7036118e+01, 7.3350151e+01, 9.1420832e+00]) ex1 = np.trunc(y_pred).reshape(5,5,3) max_value = np.amax(ex1) min_value = np.amin(ex1) average = 1/2*(min_value + max_value) mean_value = np.mean(ex1) print(f"max: {max_value}\nmin: {min_value}\naverage: {average}\nmean: {mean_value}") x = 5 y = 5 z = 3 axes = [5, 5, 3] data = np.ones(axes, dtype=bool) alpha = 0.5 colors = np.empty(axes + [4]) for x1 in range(x): for y1 in range(y): for z1 in range(z): if ex1[x1][y1][z1] >= average: colors[x1][y1][z1] = [1, 0, 0, alpha] elif ex1[x1][y1][z1] > mean_value: colors[x1][y1][z1] = [1, 1, 0, alpha] elif ex1[x1][y1][z1] <= mean_value: colors[x1][y1][z1] = [0, 0, 1, alpha] fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.voxels(data, facecolors=colors, edgecolors='grey') ax.axis('on') ax.set_aspect('auto') plt.show()
解决方案
要实现带渐变热力效果的3D单元格立方体,核心是用**颜色映射(colormap)**替代固定三色划分,让每个单元格颜色随数值连续渐变,同时强化单元格分割显示。以下是修改后的代码:
%matplotlib notebook %matplotlib inline from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt import matplotlib.cm as cm from matplotlib.colors import Normalize import numpy as np # 预测数据 y_pred = ([-3.4942558e+01, -1.0922590e+01, -9.4551229e+00, -2.6156654e+01, 1.1722648e+01, 6.4425749e-01, -1.1141028e+01, 5.9728470e+01, -4.5249408e-01, -8.7741699e+00, 9.9452820e+00, -2.8595707e+00, 2.6979692e+00, 7.9802217e+00, -1.1204488e+00, -4.5213123e+01, -7.1909481e-01, -8.4901733e+00, -9.2283611e+00, 5.0730385e+01, -7.9520082e-01, 1.4589276e+02, 8.4267479e+01, -6.7399621e+00, 2.1536992e+02, 5.0958019e+01, -7.7071385e+00, 8.4650040e+01, 2.5421507e+01, -4.1403370e+00, -8.5559702e+00, 5.5478176e+01, -1.0955868e+01, 3.1425345e+02, 1.9285686e+02, 4.6105843e+00, 6.6680554e+02, 2.7745572e+02, 1.2241451e+01, 5.1578967e+02, 1.8129390e+02, 7.3322144e+00, 1.2733205e+02, 4.4435711e+01, -2.0441423e-01, 8.3673248e+01, 1.7386259e+02, -1.6146477e-01, 5.9598431e+02, 5.7501422e+02, 4.7413929e+01, 7.6495886e+02, 6.5124884e+02, 7.9399048e+01, 4.0769174e+02, 3.2358469e+02, 3.6726327e+00, 7.5896362e+01, 9.8999245e+01, -1.7699455e+00, 1.0632815e+02, 2.3123619e+02, 4.5826878e+01, 3.6063211e+02, 5.6004309e+02, 1.3757048e+02, 3.7029037e+02, 5.5426331e+02, 1.0625824e+02, 1.7360068e+02, 2.6583237e+02, 2.0798336e+01, 4.7036118e+01, 7.3350151e+01, 9.1420832e+00]) # 重塑为5x5x3的三维数组,保留原始浮点值(避免截断丢失精度) ex1 = np.array(y_pred).reshape(5,5,3) max_value = np.amax(ex1) min_value = np.amin(ex1) print(f"max: {max_value}\nmin: {min_value}") # 设置坐标轴维度 axes = [5, 5, 3] data = np.ones(axes, dtype=bool) alpha = 0.7 # 调整透明度,让内部单元格可见 # 创建归一化器和颜色映射 norm = Normalize(vmin=min_value, vmax=max_value) cmap = cm.viridis # 可替换为plasma、inferno等其他颜色映射 # 生成每个单元格的颜色 colors = np.empty(axes + [4]) for x1 in range(axes[0]): for y1 in range(axes[1]): for z1 in range(axes[2]): # 归一化数值后映射为对应RGBA颜色 rgba = cmap(norm(ex1[x1][y1][z1])) rgba[3] = alpha # 设置透明度 colors[x1][y1][z1] = rgba # 绘制3D立方体 fig = plt.figure(figsize=(10,8)) ax = fig.add_subplot(111, projection='3d') # 绘制单元格,设置边缘颜色增强分割感 ax.voxels(data, facecolors=colors, edgecolors='lightgrey', linewidth=0.5) # 设置坐标轴标签 ax.set_xlabel('X轴') ax.set_ylabel('Y轴') ax.set_zlabel('Z轴') # 添加颜色条,对应数值与颜色关系 sm = cm.ScalarMappable(norm=norm, cmap=cmap) sm.set_array([]) fig.colorbar(sm, ax=ax, shrink=0.6, pad=0.1) ax.axis('on') ax.set_aspect('auto') plt.show()
关键改动说明
- 保留原始数值精度:移除
np.trunc(),避免截断导致的颜色渐变失真 - 连续颜色映射:用
Normalize将数值归一化后,通过matplotlib内置颜色映射生成渐变色彩,更贴合热力图需求 - 强化单元格分割:设置
edgecolors='lightgrey'和linewidth=0.5,让每个单元格边界清晰可辨 - 添加颜色条:直观展示数值与颜色的对应关系,提升可视化可读性
- 调整透明度:
alpha=0.7确保内部单元格也能被观察到
内容的提问来源于stack exchange,提问作者Said Tojiboev
相关产品推荐
相关产品推荐

