基本绘图:柱状图

柱状图(垂直条形图)是展示分类数据对比的经典图表,用矩形柱的高度表示数值大小。 Matplotlib 的 plt.bar() 函数提供了灵活的柱状图绘制能力,支持分组、堆叠、误差线等高级功能。

📊 1. 基础柱状图

最简单的柱状图:传入类别名称和对应的数值:

import matplotlib.pyplot as plt

categories = ['北京', '上海', '广州', '深圳']
values = [210, 290, 180, 250]

plt.bar(categories, values)
plt.title('基础柱状图 - 城市销售额')
plt.xlabel('城市')
plt.ylabel('销售额 (万元)')
plt.show()
✔️ 默认柱宽0.8,颜色为蓝色。

🎨 2. 柱状图样式定制

bar() 支持丰富的样式参数:

参数说明示例
color柱体颜色(可统一或序列)color='steelblue'color=['red','green','blue']
edgecolor边框颜色edgecolor='black'
linewidth边框线宽linewidth=1.5
width柱宽 (0~1之间,默认0.8)width=0.6
alpha透明度alpha=0.7
示例:定制颜色、边框和宽度
categories = ['A', 'B', 'C', 'D']
values = [25, 40, 30, 35]

plt.bar(categories, values,
        color='lightcoral',
        edgecolor='darkred',
        linewidth=2,
        width=0.5,
        alpha=0.8)
plt.title('定制样式的柱状图')
plt.show()

👥 3. 分组柱状图(并列)

用于比较多个系列在同一类别下的数值。通过调整柱子的 x 坐标位置实现:

import numpy as np

categories = ['2019', '2020', '2021', '2022']
series1 = [20, 25, 32, 38]  # 产品A
series2 = [18, 22, 28, 35]  # 产品B
series3 = [15, 20, 25, 30]  # 产品C

x = np.arange(len(categories))  # [0,1,2,3]
width = 0.25

fig, ax = plt.subplots(figsize=(10, 6))
bars1 = ax.bar(x - width, series1, width, label='产品A', color='#1f77b4')
bars2 = ax.bar(x, series2, width, label='产品B', color='#ff7f0e')
bars3 = ax.bar(x + width, series3, width, label='产品C', color='#2ca02c')

ax.set_xlabel('年份')
ax.set_ylabel('销量 (万件)')
ax.set_title('分组柱状图 - 各产品年度销量')
ax.set_xticks(x)
ax.set_xticklabels(categories)
ax.legend()

plt.show()
✔️ 通过 x - width, x, x + width 实现三组并排。

🥞 4. 堆叠柱状图

使用 bottom 参数将多个系列上下堆叠,展示总量与构成:

categories = ['Q1', 'Q2', 'Q3', 'Q4']
online = [12, 15, 14, 18]
offline = [10, 12, 11, 15]

plt.bar(categories, online, label='线上', color='#4CAF50')
plt.bar(categories, offline, bottom=online, label='线下', color='#FF9800')

plt.title('堆叠柱状图 - 各季度销售额构成')
plt.ylabel('销售额 (万元)')
plt.legend()
plt.show()
✔️ bottom 参数指定第二个系列的起始高度为第一个系列的高度。

🏷️ 5. 为柱状图添加数据标签

遍历柱体对象,使用 text() 在柱顶添加数值:

categories = ['A', 'B', 'C', 'D']
values = [25, 40, 30, 35]

bars = plt.bar(categories, values, color='skyblue', edgecolor='black')

# 添加数据标签
for bar in bars:
    height = bar.get_height()
    plt.text(bar.get_x() + bar.get_width()/2., height + 0.5,
             f'{height}', ha='center', va='bottom', fontsize=10)

plt.title('带数据标签的柱状图')
plt.ylim(0, max(values) * 1.1)  # 预留标签空间
plt.show()

📏 6. 添加误差线

适用于展示数据的变异范围(如标准差、标准误):

categories = ['A', 'B', 'C', 'D']
means = [25, 40, 30, 35]
errors = [3, 5, 2, 4]  # 误差幅度

plt.bar(categories, means, yerr=errors, capsize=5,
        color='lightgreen', edgecolor='darkgreen', linewidth=1.5,
        error_kw={'elinewidth': 2, 'ecolor': 'red'})  # 误差线样式

plt.title('带误差线的柱状图')
plt.show()
✔️ yerr 指定垂直误差,capsize 控制端帽大小。

🔄 7. 处理长类别标签

当类别名称较长时,可以旋转 x 轴刻度避免重叠:

categories = ['非常长的类别名称A', '非常长的类别名称B', '非常长的类别名称C', '非常长的类别名称D']
values = [25, 40, 30, 35]

plt.bar(categories, values)
plt.xticks(rotation=45, ha='right')  # 旋转45度,右对齐
plt.title('旋转标签避免重叠')
plt.tight_layout()  # 自动调整边距
plt.show()

⬅️ 8. 拓展:水平柱状图

如果类别名称很长,水平柱状图(barh)是更好的选择:

categories = ['电子产品', '服装鞋帽', '食品饮料', '家居用品', '美妆个护']
values = [420, 380, 290, 350, 210]

plt.barh(categories, values, color='lightcoral')
plt.title('水平柱状图(条形图)')
plt.xlabel('销售额 (万元)')
plt.tight_layout()
plt.show()

📌 9. 综合案例

import numpy as np
import matplotlib.pyplot as plt

# 数据
categories = ['2019', '2020', '2021', '2022']
exp_A = [22, 28, 35, 42]   # 实验组A
exp_B = [20, 26, 33, 40]   # 实验组B
ctrl = [18, 22, 28, 35]    # 对照组

errors_A = [1.5, 2, 2.5, 3]
errors_B = [1.2, 1.8, 2.2, 2.8]
errors_ctrl = [1, 1.5, 2, 2.5]

x = np.arange(len(categories))
width = 0.25

fig, ax = plt.subplots(figsize=(10, 6))

bars_A = ax.bar(x - width, exp_A, width, yerr=errors_A, capsize=3,
                label='实验组A', color='#1f77b4', edgecolor='black')
bars_B = ax.bar(x, exp_B, width, yerr=errors_B, capsize=3,
                label='实验组B', color='#ff7f0e', edgecolor='black')
bars_ctrl = ax.bar(x + width, ctrl, width, yerr=errors_ctrl, capsize=3,
                   label='对照组', color='#2ca02c', edgecolor='black')

# 添加数据标签
for bars in [bars_A, bars_B, bars_ctrl]:
    for bar in bars:
        height = bar.get_height()
        ax.text(bar.get_x() + bar.get_width()/2., height + 1,
                f'{height}', ha='center', va='bottom', fontsize=9)

ax.set_xlabel('年份')
ax.set_ylabel('观测值')
ax.set_title('分组柱状图 - 实验数据对比 (含误差线)')
ax.set_xticks(x)
ax.set_xticklabels(categories)
ax.legend()

plt.tight_layout()
plt.show()
✔️ 结合分组、误差线和数据标签,展示更丰富的信息。

💾 10. 保存图表

使用 savefig() 保存为常见格式:

plt.savefig('bar_chart.png', dpi=300, bbox_inches='tight')   # 高清PNG
plt.savefig('bar_chart.pdf', bbox_inches='tight')            # 矢量PDF

柱状图是展示分类数据对比的核心工具,掌握分组、堆叠、标签和误差线的用法,能让你的数据故事更加清晰有力。下一章我们将学习直方图,用于展示连续数据的分布。