在数据可视化的工具箱里,3D 图表总能带来眼前一亮的效果 —— 它突破了二维平面的限制,用立体空间展示多维度数据关系,让复杂的数据层级一目了然。今天我们要解锁的「3D 堆叠条形图」,就是一种能同时呈现类别、子类别、数值大小的强大可视化工具,特别适合展示具有分层结构的数据。无论是商业报表中的多维度业绩分析,还是科研数据中的多指标对比,它都能让你的数据呈现瞬间高级起来~
先聊聊这种图表的独特优势:
适合场景举例:
先奉上完整代码,我们将像拆解乐高积木一样解析每个关键模块:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Generate random data
num_x = 10
num_y = 10
num_stacks = 5
data = np.random.randint(0, 10, size=(num_x, num_y, num_stacks))
# Set up figure and 3D axis
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x_positions = np.arange(1, num_x + 1)
y_positions = np.arange(1, num_y + 1)
dx = dy = 0.5 # width and depth of the bars
# Plot stacked bars
for i, x in enumerate(x_positions):
for j, y in enumerate(y_positions):
bottom = 0
for k in range(num_stacks):
dz = data[i, j, k]
ax.bar3d(x, y, bottom, dx, dy, dz, alpha=0.8)
bottom += dz
# Set labels and title
ax.set_xlabel('Variable1')
ax.set_ylabel('Variable2')
ax.set_zlabel('Variable3')
ax.set_title('3D Stacked Bar Plot')
plt.show()
num_x = 10
num_y = 10
num_stacks = 5
data = np.random.randint(0, 10, size=(num_x, num_y, num_stacks))
num_x
),比如 10 个销售区域num_y
),比如 10 种产品num_stacks
),比如 5 个季度的指标data
即可:data = your_3d_data # 例如从文件读取的numpy数组
若数据是二维表格(如 Excel 中的长表格),需要先转换为三维结构。例如,假设你的数据是:
Variable1 | Variable2 | Stack1 | Stack2 | Stack3 |
---|---|---|---|---|
1 | 1 | 5 | 3 | 2 |
1 | 2 | 4 | 6 | 1 |
... | ... | ... | ... | ... |
可以用pandas 重组数据: |
import pandas as pd
df = pd.read_csv('your_data.csv')
num_x = df['Variable1'].nunique()
num_y = df['Variable2'].nunique()
num_stacks = 3 # 假设堆叠层数为3
data = df.pivot_table(
values=['Stack1', 'Stack2', 'Stack3'],
index='Variable1',
columns='Variable2'
).values.transpose(1, 0, 2) # 调整维度顺序为(num_x, num_y, num_stacks)
projection='3d'
是激活三维坐标轴的关键,Matplotlib 的Axes3D
类会负责处理立体空间的渲染。fig.set_size_inches(10, 8)
调整画布大小,数据量较大时建议增大画布,避免条形过于拥挤。x_positions = np.arange(1, num_x + 1)
y_positions = np.arange(1, num_y + 1)
dx = dy = 0.5 # 条形的宽度和深度
x_positions
和y_positions
定义了每个基底条形在 x-y 平面的位置,默认从 1 开始(避免坐标 0 导致的视觉混淆)。dx
和dy
控制条形的宽度和深度(三维中的 x 和 y 方向尺寸),数值越小,条形越纤细;建议设置为小于 1 的值(如 0.8),留出条形间的间隔。for i, x in enumerate(x_positions):
for j, y in enumerate(y_positions):
bottom = 0 # 堆叠基底高度初始化为0
for k in range(num_stacks):
dz = data[i, j, k] # 第k层的高度
ax.bar3d(x, y, bottom, dx, dy, dz, alpha=0.8) # 绘制单层条形
bottom += dz # 基底高度累加上当前层高度
ax.bar3d
的参数解析:
x, y
:条形在 x-y 平面的中心坐标bottom
:条形底部在 z 轴的起始位置(即下层条形的顶部高度)dx, dy
:条形在 x 和 y 方向的宽度(建议保持一致以避免视觉变形)dz
:条形在 z 轴的高度(即当前层的数据值)alpha=0.8
:设置透明度,避免多层堆叠时颜色过深遮挡数据当前代码使用默认颜色,可能导致多层堆叠时难以区分。可以通过color
参数自定义每层颜色:
# 定义每层的颜色(建议使用明度差异大的颜色)
stack_colors = ['#FF5733', '#33FF57', '#3357FF', '#FF33F7', '#F7FF33']
# 在绘制时传入颜色
ax.bar3d(x, y, bottom, dx, dy, dz, color=stack_colors[k], alpha=0.8)
ax.set_xticks(x_positions) # 设置x轴刻度为实际位置
ax.set_yticks(y_positions) # 设置y轴刻度为实际位置
ax.tick_params(axis='x', labelsize=8, rotation=15) # 旋转x轴标签避免重叠
ax.tick_params(axis='y', labelsize=8, rotation=10) # 微调y轴标签角度
ax.view_init(elev=30, azim=45) # elev:仰角,azim:方位角
# 常用组合:
# 正前方视角:elev=90, azim=0
# 俯视视角:elev=60, azim=30
for i, x in enumerate(x_positions):
for j, y in enumerate(y_positions):
bottom = 0
for k in range(num_stacks):
dz = data[i, j, k]
# 计算条形顶部中心坐标
x_center = x + dx/2
y_center = y + dy/2
z_top = bottom + dz/2
ax.text(x_center, y_center, z_top, f'{dz}', ha='center', va='center')
bottom += dz
ax.grid(False) # 关闭默认网格,避免干扰
ax.xaxis.set_pane_color((1.0, 1.0, 1.0, 0.0)) # 透明化坐标轴背景
ax.yaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
ax.zaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
alpha=0.6
)view_init
设置仰角和方位角)dx/dy
值,或关闭不必要的网格和背景渲染plt.cm.tab10
)Matplotlib 默认支持鼠标交互:
plt.ion()
(交互模式),可以在 Jupyter Notebook 中实时调整视角。from matplotlib.animation import FuncAnimation
def update(frame):
ax.view_init(elev=30, azim=frame) # 动态改变方位角
return fig,
ani = FuncAnimation(fig, update, frames=np.linspace(0, 360, 30), repeat=True)
ani.save('3d_bar_animation.gif', writer='pillow')
将 3D 堆叠图与 2D 趋势图组合,形成多视图仪表盘:
fig, (ax3d, ax2d) = plt.subplots(1, 2, figsize=(15, 6), subplot_kw={'projection': '3d'})
# 在ax3d绘制堆叠图,在ax2d绘制x轴总和的折线图
3D 堆叠条形图就像一个数据舞台,每个条形都是舞台上的舞者,用高度和颜色演绎数据的故事。通过今天的教程,你已经掌握了从数据准备到细节优化的全流程,现在只差替换成你自己的数据啦!
替换数据的关键步骤回顾:
[num_x, num_y, num_stacks]
data = np.random.randint(...)
这一行,直接赋值为你的数据set_xlabel
/set_ylabel
/set_zlabel
)和标题快去试试吧!无论是分析商业数据还是科研成果,这种立体可视化方式都会让你的报告瞬间提升一个档次~✨
如果在实践中遇到问题,或者想分享你的创意可视化案例,欢迎在评论区留言!让我们一起在数据的三维世界里探索更多可能~