Python数据可视化:matplotlib从入门到美化
文章目录
- Python数据可视化:matplotlib从入门到美化
-
- 前言
- 一、安装与基础架构
- 二、折线图:趋势与变化
- 三、柱状图:对比与排名
- 四、饼图:占比与构成
- 五、散点图:相关性与分布
- 六、中文显示问题解决
- 七、多子图与保存
- 总结
- [✅ 亮点总结](#✅ 亮点总结)
- 适用场景
- 扩展方向
前言
"一图胜千言",数据可视化是数据分析的最后一环,也是最直观的表达方式。matplotlib是Python最老牌、最基础的绘图库,几乎所有Python可视化工具(seaborn、pandas.plot等)都建立在它之上。掌握matplotlib就等于掌握了Python绘图的底层能力------理解Figure和Axes的架构后,你可以随心所欲地定制图表的每个细节。本文聚焦matplotlib的四大核心图表(折线图、柱状图、饼图、散点图)和中文显示问题,带你系统学会数据可视化。
matplotlib vs seaborn:matplotlib提供了"画笔级"的控制力------你可以在像素级别调整图表元素;seaborn提供了"智能相机级"的便捷------默认样式美观、统计图表一行搞定。学习路径建议先掌握matplotlib的基础架构,再学习seaborn的高层封装,这样遇到seaborn无法满足的定制需求时,能直接回到matplotlib层面修改。
一、安装与基础架构
matplotlib的绘图基于**Figure(画布)和Axes(坐标系)**的核心概念。一张Figure可以包含多个Axes(子图),每个Axes有自己的坐标轴、标题、图例等元素。理解这个层级关系是掌握matplotlib的关键------很多初学者在"这个图表的标题为什么没显示"这类问题上卡住,往往是因为对Figure/Axes的操作边界没搞清。
bash
pip install matplotlib
matplotlib提供两种绘图方式:pyplot 接口(面向过程的快速绘图)和面向对象接口(精确控制每个元素)。以下是两者的对比:
python
import matplotlib.pyplot as plt
import numpy as np
# 快速绘图(pyplot接口)
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.plot(x, y, label="sin(x)")
plt.title("正弦函数")
plt.xlabel("x")
plt.ylabel("y")
plt.legend()
plt.grid(True)
plt.show()
# 面向对象绘图(推荐用于复杂图表)
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(x, y, color="blue", linewidth=2, linestyle="--")
ax.set_title("正弦函数(面向对象方式)")
ax.set_xlabel("x")
ax.set_ylabel("y")
plt.show()
pyplot vs 面向对象方式 :pyplot方式(
plt.plot(...))简洁但隐式维护了一个"当前画布和Axes"的状态,适合快速探索;面向对象方式(fig, ax = plt.subplots())显式操作具体的Axes对象,适合需要精确控制多子图的场景。专业数据项目中,更推荐面向对象方式------它不会出现"我给子图2设了标题,但标题跑到了子图1"这类诡异问题。
Figure的尺寸 :figsize=(8, 4)单位是英寸。对于论文插图,通常需要根据期刊的列宽来精确设定(单栏约3.5英寸,双栏约7英寸);对于PPT展示,一般取(10, 6)或(12, 8)以获得较大显示区域。
二、折线图:趋势与变化
折线图适合展示数据随时间变化的趋势:
python
months = ["1月", "2月", "3月", "4月", "5月", "6月"]
sales_A = [12000, 15000, 13000, 18000, 20000, 22000]
sales_B = [8000, 10000, 12000, 11000, 15000, 17000]
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(months, sales_A, marker="o", linewidth=2, label="产品A", color="#4472C4")
ax.plot(months, sales_B, marker="s", linewidth=2, label="产品B", color="#ED7D31")
# 添加数据标签
for i, (a, b) in enumerate(zip(sales_A, sales_B)):
ax.annotate(f"{a}", (i, a), textcoords="offset points", xytext=(0, 10), ha="center")
ax.annotate(f"{b}", (i, b), textcoords="offset points", xytext=(0, -15), ha="center")
ax.set_title("上半年产品销售趋势", fontsize=16, fontweight="bold")
ax.set_xlabel("月份", fontsize=12)
ax.set_ylabel("销售额(元)", fontsize=12)
ax.legend(fontsize=12)
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
数据标签的重要性 :在业务汇报中,只有线条是不够的------领导需要看到具体数字。
ax.annotate()可以在数据点的附近放置文字标签,textcoords="offset points"让标签位置相对于数据点偏移若干像素点。注意标签的摆放要避免重叠------当两条线交叉时,需要手动调整标签的偏移方向。
颜色选择建议 :#4472C4(蓝)和#ED7D31(橙)是经典的可视化配色组合,色盲友好且对比度足够。不要使用红绿直接配色------约8%的男性有红绿色盲,你的图表会让他们完全无法区分。这是数据可视化的基本职业素养。
三、柱状图:对比与排名
python
categories = ["技术部", "销售部", "市场部", "运营部", "财务部"]
attendance = [95, 88, 92, 90, 97]
fig, ax = plt.subplots(figsize=(10, 5))
bars = ax.bar(categories, attendance, color=["#4472C4", "#ED7D31", "#A5A5A5", "#FFC000", "#5B9BD5"])
# 柱顶标注数值
for bar in bars:
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2., height + 0.5,
f"{height}%", ha="center", va="bottom", fontsize=11)
ax.set_title("各部门出勤率统计", fontsize=16, fontweight="bold")
ax.set_ylabel("出勤率(%)")
ax.set_ylim(0, 105)
plt.tight_layout()
plt.show()
# 分组柱状图
x = np.arange(len(categories))
width = 0.35
fig, ax = plt.subplots(figsize=(10, 5))
bars1 = ax.bar(x - width/2, [95, 88, 92, 90, 97], width, label="上半年", color="#4472C4")
bars2 = ax.bar(x + width/2, [90, 85, 95, 88, 93], width, label="下半年", color="#ED7D31")
ax.set_xticks(x)
ax.set_xticklabels(categories)
ax.legend()
plt.show()
分组柱状图的构建原理 :
x - width/2和x + width/2通过在x轴位置附近前后偏移实现并排显示。width=0.35表示每个柱子的宽度,两柱间距为width,留出视觉间隙。这是柱状图布局的经典模式,几乎所有的分组/堆叠柱状图都基于这个范式。
常见错误 :忘记调用ax.set_xticks(x)和ax.set_xticklabels(categories)设置x轴刻度标签。在分组柱状图中,x轴刻度不再是0,1,2,3...而是被位移后的位置------如果你省略了这两行,x轴标签会显示为0.5, 1.5, 2.5...而不是部门名称。
四、饼图:占比与构成
python
labels = ["工资", "租金", "市场推广", "设备采购", "其他"]
sizes = [45, 20, 15, 12, 8]
explode = (0.05, 0, 0, 0, 0) # 突出第一块
colors = ["#4472C4", "#ED7D31", "#A5A5A5", "#FFC000", "#5B9BD5"]
fig, ax = plt.subplots(figsize=(8, 6))
wedges, texts, autotexts = ax.pie(
sizes, labels=labels, explode=explode, colors=colors,
autopct="%1.1f%%", startangle=90, pctdistance=0.85,
textprops={"fontsize": 12}
)
# 中心绘制圆形形成甜甜圈效果
centre_circle = plt.Circle((0, 0), 0.60, fc="white")
ax.add_artist(centre_circle)
ax.set_title("公司支出构成", fontsize=16, fontweight="bold")
plt.tight_layout()
plt.show()
饼图的争议 :数据可视化领域有一个共识------饼图适合展示3-5个类别的占比,超过7个类别则应当考虑柱状图替代。因为人的眼睛对扇形角度大小的判断精度远低于对柱状图高度差的判断。
explode参数用于突出强调某一块(通常是最重要的那个类别),但需要注意不要explode太多块,否则图表会支离破碎。
甜甜圈效果 :在饼图中心覆盖一个白色圆形(plt.Circle((0,0), 0.60, fc="white")),就得到了"甜甜圈图"。这比纯饼图更适合展示占比信息------中空部分可以用来放置总计数字或标题,视觉上也更现代。
五、散点图:相关性与分布
python
np.random.seed(42)
ad_cost = np.random.uniform(1000, 10000, 50)
revenue = ad_cost * 3.5 + np.random.normal(0, 3000, 50)
fig, ax = plt.subplots(figsize=(8, 6))
scatter = ax.scatter(ad_cost, revenue, c=revenue/ad_cost, cmap="viridis",
s=80, alpha=0.7, edgecolors="white", linewidth=0.5)
# 添加趋势线
z = np.polyfit(ad_cost, revenue, 1)
p = np.poly1d(z)
ax.plot(sorted(ad_cost), p(sorted(ad_cost)), "r--", alpha=0.7, linewidth=2)
ax.set_title("广告投入与营收关系", fontsize=16, fontweight="bold")
ax.set_xlabel("广告投入(元)")
ax.set_ylabel("营收(元)")
cbar = plt.colorbar(scatter, ax=ax)
cbar.set_label("投入产出比")
fig.tight_layout()
plt.show()
np.polyfit 的趋势线 :
np.polyfit(x, y, 1)对数据点拟合一条一阶多项式(直线),np.poly1d生成可调用的多项式函数。这条趋势线在业务场景中非常有用------它能直观展示两个变量之间是否存在正向/负向关联,以及关联强度。
散点图的颜色映射 :c=revenue/ad_cost用第三个变量(投入产出比)为数据点着色,cmap='viridis'指定颜色渐变方案。这让二维散点图增加了第三个维度的信息(类似三维效果),在探索性数据分析中非常有用。
六、中文显示问题解决
matplotlib默认不支持中文,需要配置字体:
python
import matplotlib.pyplot as plt
# 方式一:全局设置(推荐)
plt.rcParams["font.sans-serif"] = ["SimHei", "Microsoft YaHei", "Arial Unicode MS"]
plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题
# 方式二:下载并使用特定字体
import matplotlib.font_manager as fm
# 查看系统可用中文字体
fonts = [f.name for f in fm.fontManager.ttflist if "Hei" in f.name or "Song" in f.name]
print(f"可用中文字体: {fonts}")
# 指定字体
plt.rcParams["font.family"] = "Microsoft YaHei"
七、多子图与保存
python
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 子图1:折线图
axes[0, 0].plot(months, sales_A, "o-", color="#4472C4")
axes[0, 0].set_title("折线图")
# 子图2:柱状图
axes[0, 1].bar(categories, attendance, color="#ED7D31")
axes[0, 1].set_title("柱状图")
# 子图3:饼图
axes[1, 0].pie(sizes, labels=labels, autopct="%1.1f%%", colors=colors)
axes[1, 0].set_title("饼图")
# 子图4:散点图
axes[1, 1].scatter(ad_cost, revenue, alpha=0.6)
axes[1, 1].set_title("散点图")
plt.tight_layout()
plt.savefig("综合图表.png", dpi=300, bbox_inches="tight") # 高分辨率保存
plt.show()
总结
matplotlib的学习路径是:理解Figure/Axes架构 -> 掌握四种核心图表 -> 解决中文显示 -> 学会样式调整。本文覆盖了折线图(趋势)、柱状图(对比)、饼图(占比)、散点图(相关性)这四种最常用的图表类型,以及全局字体配置和多子图布局。建议将常用的样式配置保存为模板代码,后续绘图时直接复用,提高效率。
✅ 亮点总结
- Figure/Axes架构是matplotlib的灵魂------Figure是画布,Axes是坐标系,理解二者关系后一切绘图都变得清晰
- 四种核心图表覆盖了最常见的分析需求:折线图看趋势、柱状图做对比、饼图看占比、散点图探相关性
- 中文显示问题通过
rcParams['font.sans-serif']一行配置即可全局解决 plt.subplots()多子图布局让你在一张图上并列展示多维度信息plt.savefig(dpi=300, bbox_inches='tight')提供出版级的高清输出能力
适用场景
- 周报/月报数据可视化:将业务指标用折线图和柱状图呈现给管理层
- 数据分析报告:在Jupyter Notebook中结合文字分析嵌入专业图表
- 学术论文配图:利用高DPI输出和灵活样式定制生成符合期刊要求的插图
扩展方向
- 动态交互图表:学习
matplotlib.animation或结合Plotly实现可交互的可视化 - 自定义图表风格:深入rcParams配置和style sheets,打造个人或团队的专属视觉风格
- 推荐阅读下一篇《Python数据可视化seaborn》,用更简洁的API生成更美观的统计图表