如何使用Matplotlib绘制带标注与统计文本的3D立方体
Matplotlib实现带统计标注的3D规格立方体方案
需求说明
现有存储产品规格的DataFrame对象df,包含4个字段:
length:长度width:宽度height:高度volume:体积
需要实现的可视化效果:- 自动计算4个字段的最小值、最大值、均值三类统计量
- 画布内渲染3D立方体作为核心展示元素
- 立方体旁放置全字段统计说明文本
- 长、宽、高三个维度旁添加带引线的数值标注
测试数据
原始数据样例
| 序号 | length | width | height | volume |
|---|---|---|---|---|
| 0 | 1.5 | 1.5 | 1.5 | 0.15 |
| 1 | 0.4 | 0.8 | 0.6 | 0.85 |
| 2 | 4.3 | 8.5 | 3.5 | 1.15 |
| 3 | 3.3 | 4.5 | 2.4 | 0.02 |
统计量计算结果
| 统计项 | length | width | height | volume |
|---|---|---|---|---|
| mean | 2.37500 | 3.82500 | 2.00000 | 0.54250 |
| min | 0.40000 | 0.80000 | 0.60000 | 0.02000 |
| max | 4.30000 | 8.50000 | 3.50000 | 1.15000 |
测试数据生成代码
import pandas as pd d = { "length": [1.5, 0.4, 4.3, 3.3], "width": [1.5, 0.8, 8.5, 4.5], "height": [1.5, 0.6, 3.5, 2.4], "volume": [0.15, 0.85, 1.15, 0.02], } df = pd.DataFrame(data=d)
预期效果参考
现有基础代码(仅实现基础立方体绘制)
注意:NumPy 1.20及以上版本已弃用
np.bool别名,运行时请替换为np.bool_避免报错
# 导入依赖库 import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import numpy as np # 定义坐标轴尺寸 axes = [5, 5, 5] # 生成立方体体素数据 data = np.ones(axes, dtype=np.bool_) # 设置透明度 alpha = 0.9 # 设置立方体颜色 colors = np.empty(axes + [4], dtype=np.float32) colors[:] = [0.9, 0.9, 0.9, alpha] # 浅灰色填充 # 初始化画布 fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # 绘制体素立方体 ax.voxels(data, facecolors=colors)
基础代码运行效果
完整可运行实现代码
import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import numpy as np import pandas as pd # 1. 加载数据并计算统计量 d = { "length": [1.5, 0.4, 4.3, 3.3], "width": [1.5, 0.8, 8.5, 4.5], "height": [1.5, 0.6, 3.5, 2.4], "volume": [0.15, 0.85, 1.15, 0.02], } df = pd.DataFrame(data=d) stats = df.agg(['mean', 'min', 'max']).T l_mean, w_mean, h_mean = stats.loc['length', 'mean'], stats.loc['width', 'mean'], stats.loc['height', 'mean'] # 2. 初始化3D画布 fig = plt.figure(figsize=(10, 8), dpi=100) ax = fig.add_subplot(111, projection='3d') # 3. 绘制以均值为尺寸的半透明立方体 grid_step = 0.5 x_grid = np.arange(0, l_mean + grid_step, grid_step) y_grid = np.arange(0, w_mean + grid_step, grid_step) z_grid = np.arange(0, h_mean + grid_step, grid_step) x, y, z = np.meshgrid(x_grid, y_grid, z_grid, indexing='ij') cube = (x < l_mean) & (y < w_mean) & (z < h_mean) # 配置立方体样式 face_color = np.array([0.85, 0.85, 0.95, 0.7]) edge_color = np.array([0.2, 0.2, 0.4, 1]) ax.voxels(cube, facecolors=face_color, edgecolors=edge_color, linewidth=1.2) # 4. 绘制三个维度的引线与标注 # X轴(长度)标注 ax.plot([0, l_mean], [0, 0], [0, 0], color='#c0392b', linewidth=2) ax.text(l_mean/2, -0.8, 0, f"Length\nmin: {stats.loc['length','min']:.2f}\nmean: {l_mean:.2f}\nmax: {stats.loc['length','max']:.2f}", color='#c0392b', ha='center', fontsize=10) # Y轴(宽度)标注 ax.plot([0, 0], [0, w_mean], [0, 0], color='#27ae60', linewidth=2) ax.text(-0.8, w_mean/2, 0, f"Width\nmin: {stats.loc['width','min']:.2f}\nmean: {w_mean:.2f}\nmax: {stats.loc['width','max']:.2f}", color='#27ae60', ha='center', fontsize=10) # Z轴(高度)标注 ax.plot([0, 0], [0, 0], [0, h_mean], color='#2980b9', linewidth=2) ax.text(-0.8, 0, h_mean/2, f"Height\nmin: {stats.loc['height','min']:.2f}\nmean: {h_mean:.2f}\nmax: {stats.loc['height','max']:.2f}", color='#2980b9', ha='center', fontsize=10) # 5. 添加体积统计文本块 vol_text = f"Volume Statistics\nmin: {stats.loc['volume','min']:.2f}\nmean: {stats.loc['volume','mean']:.2f}\nmax: {stats.loc['volume','max']:.2f}" ax.text(l_mean + 1, w_mean/2, h_mean/2, vol_text, bbox=dict(facecolor='white', alpha=0.8, edgecolor='gray'), fontsize=11, ha='left') # 6. 调整视图参数 ax.set_xlim(-1, l_mean + 3) ax.set_ylim(-1, w_mean + 2) ax.set_zlim(-1, h_mean + 2) ax.set_xlabel('X (Length)', labelpad=10) ax.set_ylabel('Y (Width)', labelpad=10) ax.set_zlabel('Z (Height)', labelpad=10) ax.view_init(elev=25, azim=-55) plt.tight_layout() plt.show()
实现要点
- 立方体以三个维度的均值为尺寸基准绘制,采用半透明填充加深色描边的样式,避免遮挡后方标注
- 三个维度的引线沿对应坐标轴绘制,用不同颜色区分维度,标注直接展示该维度的最小/均值/最大值
- 体积统计文本放置在立方体右侧,添加半透明白色背景,避免和3D图形元素重叠导致文字看不清
- 调整坐标轴范围预留足够的标注空间,设置视角参数匹配常规3D立方体观察角度,避免内容裁切
内容的提问来源于stack exchange,提问作者Test
相关产品推荐
相关产品推荐

