You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Matplotlib分组柱状图添加轻微3D效果?附3D实现方案

问题说明

我有如下DataFrame数据:

YEAR  CODE      ANOM%
    0    1964  152101 -85.294118
    1    1965  152101 -62.352941
    2    1965  152111 -85.862069
    3    1966  152101 -81.352941
    4    1966  152111 -77.873563
    ..    ...     ...        ...
    108  2020  152101 -38.823529
    109  2021  152101 -59.352941
    110  2021  152111  74.137931
    111  2022  152101 -95.235294
    112  2022  152111 -76.436782

[113 rows x 3 columns]

已经用以下代码生成透视表:

df.sort_values('YEAR', axis=0, ascending=True, inplace=True, ignore_index=True)

years = df["YEAR"].unique()
prv= df["CODE"].unique()

# 分类转换
df["YEAR"] = pd.Categorical(df["YEAR"], categories=years)
df["CODE"] = pd.Categorical(df["CODE"], categories=prv)

# 创建透视表
df_pivot = pd.pivot_table(
    df,
    values="ANOM%", 
    index="YEAR", 
    columns="CODE", 
    aggfunc=np.sum 
)

df_pivot.columns = df_pivot.columns.add_categories('AVERAGE')
df_pivot['AVERAGE']=df_pivot.mean(axis=1).astype(int)

接着用这段代码绘制分组柱状图时,尝试通过depthshade=True添加轻微3D效果,结果报错:AttributeError: Rectangle.set() got an unexpected keyword argument 'depthshade'。当前使用Matplotlib 3.7.0版本,需要两个解决方案:

  1. 如何实现柱状图的轻微3D效果(非完整3D)
  2. 若必须绘制完整3D柱状图,该怎么操作

解决方案

一、模拟轻微3D效果(2D伪立体)

depthshade是Matplotlib 3D绘图的专属参数,2D柱状图不支持,所以会报错。要做轻微立体效果,用2D图形模拟即可,推荐两种方法:

方法1:叠加阴影柱

在主柱子下方绘制一层颜色更深、轻微偏移的柱子,模拟立体侧面,简单易实现:

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure('Grouped Bars', figsize=(16,10), dpi=100)
ax1 = fig.add_axes([0.1, 0.1, 0.85, 0.75])

bar_width = 0.2
x = np.arange(len(df_pivot.index))
n_cols = len(df_pivot.columns)

# 遍历每一列数据,先画阴影再画主柱
for i, col in enumerate(df_pivot.columns):
    # 阴影柱:向右向下偏移一点,用深灰色
    ax1.bar(x + i*bar_width + 0.02, df_pivot[col], width=bar_width, 
            color='#333333', alpha=0.5, zorder=0)
    # 主柱:正常位置,保留原颜色设置
    color = 'black' if col != 'AVERAGE' else 'red'
    ax1.bar(x + i*bar_width, df_pivot[col], width=bar_width, 
            color=color, edgecolor='black', linewidth=2, alpha=0.7, zorder=1)

# 配置轴标签和图例
ax1.set_xticks(x + bar_width*(n_cols-1)/2)
ax1.set_xticklabels(df_pivot.index, fontsize=12)
ax1.legend(df_pivot.columns, fontsize=12)
plt.show()

方法2:手动绘制斜面矩形

用matplotlib.patches模块绘制柱子的主体和斜面,模拟更精细的立体效果:

from matplotlib.patches import Rectangle, Polygon

fig, ax1 = plt.subplots(figsize=(16,10), dpi=100)
x = np.arange(len(df_pivot.index))
bar_width = 0.2
depth = 0.03  # 斜面的深度,控制立体程度

for i, col in enumerate(df_pivot.columns):
    # 主色和深色(用于斜面)
    color = 'black' if col != 'AVERAGE' else 'red'
    dark_color = '#333333' if col != 'AVERAGE' else '#cc0000'
    
    # 遍历每一年的数据,绘制单个柱子
    for j, val in enumerate(df_pivot[col]):
        # 绘制柱子主体
        main_rect = Rectangle((x[j]+i*bar_width, 0), bar_width, val, 
                             color=color, edgecolor='black', linewidth=1, alpha=0.7)
        ax1.add_patch(main_rect)
        
        # 绘制右侧斜面
        if val > 0:
            right_verts = [
                (x[j]+i*bar_width+bar_width, 0),
                (x[j]+i*bar_width+bar_width+depth, depth),
                (x[j]+i*bar_width+bar_width+depth, val+depth),
                (x[j]+i*bar_width+bar_width, val)
            ]
        else:
            # 负值柱子的斜面方向调整
            right_verts = [
                (x[j]+i*bar_width+bar_width, 0),
                (x[j]+i*bar_width+bar_width+depth, -depth),
                (x[j]+i*bar_width+bar_width+depth, val-depth),
                (x[j]+i*bar_width+bar_width, val)
            ]
        right_poly = Polygon(right_verts, color=dark_color, alpha=0.5)
        ax1.add_patch(right_poly)
        
        # 绘制顶部斜面
        top_verts = [
            (x[j]+i*bar_width, val),
            (x[j]+i*bar_width+depth, val+depth),
            (x[j]+i*bar_width+bar_width+depth, val+depth),
            (x[j]+i*bar_width+bar_width, val)
        ]
        top_poly = Polygon(top_verts, color=dark_color, alpha=0.5)
        ax1.add_patch(top_poly)

# 调整轴范围和标签
ax1.set_xlim(x[0]-0.5, x[-1]+n_cols*bar_width+0.5)
ax1.set_ylim(df_pivot.min().min()-10, df_pivot.max().max()+10)
ax1.set_xticks(x + bar_width*(n_cols-1)/2)
ax1.set_xticklabels(df_pivot.index, fontsize=12)
ax1.legend(df_pivot.columns, fontsize=12)
plt.show()

二、绘制完整3D柱状图

如果需要真正的3D效果,使用Matplotlib的3D轴组件,需要处理坐标映射:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(16,10), dpi=100)
ax = fig.add_subplot(111, projection='3d')

# 生成x、y轴的网格坐标
x = np.arange(len(df_pivot.index))
y = np.arange(len(df_pivot.columns))
xpos, ypos = np.meshgrid(x, y)
xpos = xpos.flatten()
ypos = ypos.flatten()
zpos = np.zeros_like(xpos)  # 柱子底部在z=0处

# 设置柱子的宽度、深度和高度
dx = dy = 0.5
dz = df_pivot.values.flatten()

# 匹配每根柱子的颜色
colors = ['black' if col != 'AVERAGE' else 'red' for col in df_pivot.columns]
colors = np.repeat(colors, len(df_pivot.index))

# 绘制3D柱状图
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color=colors, alpha=0.7, edgecolor='black')

# 配置轴标签
ax.set_xticks(x + dx/2)
ax.set_xticklabels(df_pivot.index, fontsize=10)
ax.set_yticks(y + dy/2)
ax.set_yticklabels(df_pivot.columns, fontsize=10)
ax.set_zlabel('ANOM%', fontsize=12)

# 调整视角,让显示更清晰
ax.view_init(elev=20., azim=-30)
plt.show()

内容的提问来源于stack exchange,提问作者Javier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 23:02:35