目录
一、课程目标
- 理解 Matplotlib 中双 Y 坐标轴图表的原理和应用场景
- 掌握柱状图和折线图的组合绘制方法
- 学会为图表添加数据标签、参考线等增强元素
- 能够根据实际数据特点设计合适的可视化方案
- 了解图表美化和细节处理的技巧
二、理论知识讲解
(一)组合图形的应用场景
- 多维度数据展示:当需要同时展示两种不同量级、不同单位的数据时
- 趋势对比分析:比较两个变量随时间或其他因素的变化趋势
- 数据关系探索:直观呈现两个变量之间的相关性或因果关系
(二)Matplotlib 双 Y 坐标轴实现原理
- 共享 X 轴:两个 Y 轴共用同一个 X 轴数据
- 独立刻度:左右两个 Y 轴可以有不同的刻度范围和单位
- 对象引用:通过twinx()方法创建共享 X 轴的第二个 Y 轴
(三)图表元素设计原则
- 数据清晰:确保每个数据点都能被准确读取
- 视觉平衡:避免图表元素过于拥挤或稀疏
- 对比明显:使用不同颜色、形状区分不同数据系列
- 信息完整:包含标题、坐标轴标签、图例等必要元素
三、代码实现演示
(一)数据准备与环境设置
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
# 设置中文字体支持
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题
# 定义数据
years = np.arange(2000, 2026)
smokers = np.array([250, 255, 260, 268, 275, 282, 290, 298, 305, 312, 320,
328, 335, 342, 348, 350, 345, 338, 330, 322, 315, 308,
300, 292, 285, 278])
# 计算同比增长率(保留两位小数)
growth_rates = np.zeros_like(years, dtype=float)
growth_rates[1:] = np.round(((smokers[1:] - smokers[:-1]) / smokers[:-1]) * 100, 2)
代码解释:
- 数据结构:使用 NumPy 数组存储年份、吸烟人数和增长率
- 增长率计算:通过公式(当前值-前值)/前值*100%计算同比增长率
- 中文支持:设置字体参数确保中文正常显示
(二)创建基础组合图表
# 创建画布和双Y坐标轴
fig, ax1 = plt.subplots(figsize=(14, 7))
ax2 = ax1.twinx()
# 绘制吸烟人数主图(柱状图)
bars = ax1.bar(years, smokers, width=0.6, color='#3274A1', label='吸烟人数(万人)')
# 绘制增长率副图(折线图)
line = ax2.plot(years[1:], growth_rates[1:], 'o-', color='#E1812C',
linewidth=2, markersize=6, label='同比增长率(%)')
# 设置坐标轴标签和标题
ax1.set_xlabel('年份', fontsize=12)
ax1.set_ylabel('吸烟人数(万人)', fontsize=12, color='#3274A1')
ax2.set_ylabel('同比增长率(%)', fontsize=12, color='#E1812C')
plt.title('某地区2000-2025年吸烟人数及同比增长率趋势图', fontsize=16)
# 设置X轴刻度和网格线
ax1.set_xticks(years)
ax1.set_xticklabels(years, rotation=45)
ax1.grid(axis='y', linestyle='--', alpha=0.7)
代码解释:
- 双 Y 轴创建:通过ax1.twinx()创建共享 X 轴的第二个 Y 轴
- 柱状图绘制:使用ax1.bar()绘制吸烟人数柱状图
- 折线图绘制:使用ax2.plot()绘制增长率折线图
- 坐标轴设置:分别设置左右 Y 轴的标签和单位
(三)添加数据标签
# 为柱状图添加数据标签
for bar in bars:
height = bar.get_height()
ax1.text(bar.get_x() + bar.get_width()/2., height + 1,
f'{height}', ha='center', va='bottom', fontsize=9)
# 为折线图添加数据标签
for x, y in zip(years[1:], growth_rates[1:]):
va = 'bottom' if y > 0 else 'top'
color = 'black' if abs(y) > 0.5 else 'gray'
ax2.annotate(f'{y:.2f}%',
(x, y),
textcoords="offset points",
xytext=(0, 8 if y > 0 else -8),
ha='center',
va=va,
fontsize=9,
color=color)
代码解释:
- 柱状图标签:使用ax1.text()在每个柱子上方添加数值
- 折线图标签:使用ax2.annotate()为每个数据点添加标签
- 智能定位:根据增长率正负自动调整标签位置
- 细节优化:增长率较小时使用灰色字体,提高可读性
(四)图表美化与增强
# 设置Y轴范围
ax1.set_ylim(200, 380)
ax2.set_ylim(-5, 5)
# 为增长率添加水平参考线(0%)
ax2.axhline(y=0, color='black', linestyle='-', alpha=0.3)
# 标记预测数据区域
ax1.axvline(x=2019.5, color='gray', linestyle='--', alpha=0.7)
ax1.text(2022, 230, '预测数据', fontsize=12, color='gray', ha='center')
# 添加图例
lines, labels = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax2.legend(lines + lines2, labels + labels2, loc='upper right')
# 美化图表
plt.tight_layout() # 调整布局
plt.subplots_adjust(top=0.9) # 为标题留出空间
# 显示图表
plt.show()
代码解释:
- Y 轴范围设置:手动设置 Y 轴范围,避免数据过于拥挤
- 参考线添加:使用ax2.axhline()添加水平参考线
- 区域标记:使用ax1.axvline()和ax1.text()标记预测数据区域
- 图例合并:合并两个 Y 轴的图例,避免重复显示
最终效果展示:
四、关键技术点总结
- 双 Y 坐标轴实现:
- 使用twinx()方法创建共享 X 轴的第二个 Y 轴
- 分别操作两个 Y 轴对象绘制不同类型的图表
2. 数据标签技巧:
- 柱状图使用text()方法添加标签
- 折线图使用annotate()方法添加标签
- 根据数据特征智能调整标签位置和样式
3. 图表美化要点:
- 选择协调的配色方案(如蓝色和橙色的对比)
- 添加参考线和区域标记辅助数据解读
- 合理设置坐标轴范围和刻度
- 优化布局和字体大小,提高可读性
五、实践练习
(一)基础练习
- 修改代码中的数据,使用自己感兴趣的数据集绘制组合图表
- 调整图表的颜色、线型和标记样式,创建不同风格的可视化效果
- 尝试添加更多的数据标签自定义选项,如字体大小、颜色和背景框
(二)进阶练习
- 在图表中添加平均值参考线,显示吸烟人数和增长率的长期平均水平
- 使用条件格式为不同区间的增长率设置不同颜色的标签
- 添加交互功能,当鼠标悬停在数据点上时显示详细信息
(三)挑战练习
- 将代码封装为函数,使其可以接受任意数据集并生成组合图表
- 添加子图,在同一画布上同时显示原始数据和增长率的分布情况
- 设计动态图表,展示数据随时间的变化过程
六、常见问题解答
1. 问题:为什么我的中文显示为方块?
解答:需要设置中文字体支持,确保系统中安装了指定的中文字体
2. 问题:如何调整图表的大小和分辨率?
解答:使用figsize参数设置图表大小,使用dpi参数设置分辨率
3. 问题:数据标签重叠怎么办?
解答:可以手动调整标签位置,或使用专门的库如adjustText自动调整
4. 问题:如何保存生成的图表?
解答:使用plt.savefig()方法保存图表为图片文件
七、课程总结
通过本节课的学习,我们掌握了以下技能:
- 使用 Matplotlib 创建双 Y 坐标轴的组合图表
- 绘制柱状图和折线图并添加数据标签
- 对图表进行美化和细节处理
- 设计适合多维度数据展示的可视化方案