Matplotlib 柱形图(Bar)完全指南
柱形图是 数据对比、排名、分布展示 的王牌工具。本教程带你从入门到 发表级,掌握 垂直/水平柱状图、堆叠、分组、误差棒、动态标注、瀑布图、双向图、艺术风格 等全部技巧。
一、基本柱形图
import matplotlib.pyplot as plt
import numpy as np
categories = ['A', 'B', 'C', 'D', 'E']
values = [3, 7, 2, 5, 8]
plt.bar(categories, values)
plt.show()
二、核心参数详解
plt.bar(categories, values,
width=0.8, # 柱宽
color='skyblue', # 颜色
edgecolor='black', # 边框
linewidth=1.2, # 边框宽度
alpha=0.9, # 透明度
label='数据') # 图例
三、水平柱形图 barh
plt.barh(categories, values,
height=0.7,
color='lightcoral',
edgecolor='darkred')
plt.xlabel('值')
plt.ylabel('类别')
plt.show()
四、颜色设置
1. 统一颜色
plt.bar(categories, values, color='steelblue')
2. 每柱不同颜色
colors = ['red', 'orange', 'yellow', 'green', 'blue']
plt.bar(categories, values, color=colors)
3. 渐变色(推荐)
from matplotlib.cm import get_cmap
cmap = get_cmap('viridis')
colors = cmap(np.linspace(0, 1, len(values)))
plt.bar(categories, values, color=colors)
五、堆叠柱形图(Stacked Bar)
group1 = [3, 7, 2, 5]
group2 = [2, 4, 3, 1]
group3 = [1, 2, 4, 3]
plt.bar(categories, group1, label='组1')
plt.bar(categories, group2, bottom=group1, label='组2')
plt.bar(categories, group3, bottom=np.array(group1)+np.array(group2), label='组3')
plt.legend()
plt.show()
bottom=控制堆叠起始高度
六、分组柱形图(Grouped Bar)
x = np.arange(len(categories))
width = 0.25
plt.bar(x - width, group1, width, label='组1', color='skyblue')
plt.bar(x, group2, width, label='组2', color='lightcoral')
plt.bar(x + width, group3, width, label='组3', color='lightgreen')
plt.xticks(x, categories)
plt.legend()
plt.show()
七、误差棒(Error Bars)
errors = [0.5, 0.8, 0.3, 0.6, 1.0]
plt.bar(categories, values,
yerr=errors,
capsize=5, # 误差棒端点小横线
error_kw={'elinewidth': 2, 'capthick': 2},
color='lightblue', edgecolor='navy')
plt.show()
八、自动标注数值
bars = plt.bar(categories, values, color='steelblue', edgecolor='black')
for bar in bars:
height = bar.get_height()
plt.text(bar.get_x() + bar.get_width()/2, height + 0.1,
f'{height}',
ha='center', va='bottom', fontsize=10, fontweight='bold')
plt.ylim(0, max(values) * 1.15)
plt.show()
九、双向柱形图(人口金字塔)
ages = ['0-10', '11-20', '21-30', '31-40', '41-50']
male = [12, 15, 18, 14, 10]
female = [11, 16, 19, 13, 9]
y = np.arange(len(ages))
plt.barh(y, [-m for m in male], height=0.8, label='男性', color='skyblue')
plt.barh(y, female, height=0.8, label='女性', color='lightpink')
plt.yticks(y, ages)
plt.xlabel('人口数量 (万人)')
plt.legend()
plt.title('人口金字塔')
plt.show()
十、瀑布图(Waterfall)
steps = ['初始', '+收入', '-成本', '+投资', '-税费', '=总计']
values = [100, 50, -30, 20, -15, 0] # 最后一项为0
colors = ['gray'] + ['green' if v > 0 else 'red' for v in values[1:-1]] + ['blue']
# 计算累计
cumsum = np.cumsum([0] + values[:-1])
bottom = cumsum
height = values[:-1] + [cumsum[-1]]
plt.bar(steps, height, bottom=bottom, color=colors, edgecolor='black')
plt.axhline(0, color='black', linewidth=0.8)
plt.title('瀑布图:利润分解')
plt.show()
十一、完整专业示例(论文级)
import matplotlib.pyplot as plt
import numpy as np
plt.style.use('seaborn-v0_8')
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 数据
cities = ['北京', '上海', '广州', '深圳', '杭州', '成都']
sales_2023 = [85, 92, 78, 88, 75, 70]
sales_2024 = [90, 88, 82, 95, 80, 76]
errors = [3, 4, 2, 5, 3, 4]
x = np.arange(len(cities))
width = 0.35
fig, ax = plt.subplots(figsize=(12, 8))
# 分组柱状图
bars1 = ax.bar(x - width/2, sales_2023, width,
label='2023年', color='#1f77b4', edgecolor='navy', linewidth=1.2,
yerr=errors, capsize=6, error_kw={'elinewidth':2, 'capthick':2})
bars2 = ax.bar(x + width/2, sales_2024, width,
label='2024年', color='#ff7f0e', edgecolor='darkred', linewidth=1.2,
yerr=errors, capsize=6, error_kw={'elinewidth':2, 'capthick':2})
# 标注数值
def autolabel(bars):
for bar in bars:
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2, height + 3,
f'{int(height)}', ha='center', va='bottom', fontsize=10, fontweight='bold')
autolabel(bars1)
autolabel(bars2)
# 美化
ax.set_xlabel('城市', fontsize=14, fontweight='bold')
ax.set_ylabel('销售额 (亿元)', fontsize=14, fontweight='bold')
ax.set_title('2023-2024年城市销售额对比分析', fontsize=18, fontweight='bold', pad=20)
ax.set_xticks(x)
ax.set_xticklabels(cities, fontsize=12)
ax.set_ylim(0, 110)
ax.legend(fontsize=12, frameon=True, fancybox=True, shadow=True)
ax.grid(True, axis='y', alpha=0.3, linestyle='--', linewidth=0.8)
ax.set_facecolor('#f8f9fa')
# 边框优化
for spine in ax.spines.values():
spine.set_linewidth(1.2)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.tight_layout()
plt.savefig('bar_pro.png', dpi=300, bbox_inches='tight', facecolor='white')
plt.show()
十二、柱形图速查表(收藏用)
# 基础
plt.bar(categories, values)
# 水平
plt.barh(categories, values)
# 堆叠
plt.bar(x, v1)
plt.bar(x, v2, bottom=v1)
# 分组
plt.bar(x-width, v1, width)
plt.bar(x+width, v2, width)
# 误差棒
plt.bar(..., yerr=errors, capsize=5)
# 标注
for bar in bars:
plt.text(bar.get_x()+bar.get_width()/2, bar.get_height(), f'{bar.get_height()}')
# 颜色渐变
colors = plt.cm.viridis(np.linspace(0,1,len(values)))
十三、常见问题解决
| 问题 | 解决方案 |
|---|---|
| 柱子太挤 | 减小 width,增大 figsize |
| 标签重叠 | plt.xticks(rotation=45) |
| 数值被截断 | plt.ylim(0, max*1.15) |
| 颜色单调 | 使用 cmap 渐变 |
| 保存裁剪 | plt.savefig(..., bbox_inches='tight') |
十四、推荐风格模板
| 场景 | 推荐设置 |
|---|---|
| 论文 | 蓝橙配色,误差棒,数值标注 |
| PPT | 粗柱,醒目颜色,alpha=0.9 |
| 仪表盘 | 水平柱,渐变色 |
| 排名图 | 降序排序,color='gold' 冠军 |
官方文档
- Bar API:https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.bar.html
- 示例图库:https://matplotlib.org/stable/gallery/statistics/index.html#bars-and-error-bars
总结:三步打造专业柱形图
# 1. 数据 + 布局
x = np.arange(len(cats))
bars = plt.bar(x, values, width=0.6, color=colors, edgecolor='black')
# 2. 标注 + 误差
for bar in bars: plt.text(...)
plt.bar(..., yerr=errors, capsize=5)
# 3. 美化输出
plt.title('标题', fontsize=16, pad=20)
plt.tight_layout()
plt.savefig('fig.png', dpi=300, bbox_inches='tight')
一键生成分组柱状图:
x = np.arange(5)
plt.bar(x-0.2, [3,7,2,5,8], 0.4, label='2023', color='skyblue')
plt.bar(x+0.2, [4,6,3,6,7], 0.4, label='2024', color='lightcoral')
plt.xticks(x, ['A','B','C','D','E'])
plt.legend()
plt.show()
需要我为你:
- 生成 10种经典柱形图模板?
- 制作 Jupyter 柱形图交互小工具(滑块切换年份)?
- 输出 LaTeX/PPT 可用代码?
告诉我你的需求!