在数据分析和机器学习中,"可视化"是理解数据、呈现结果的核心环节。matplotlib作为Python最经典的可视化库,以其灵活的绘图能力和丰富的图表类型,成为数据从业者的必备工具。无论是简单的折线图、散点图,还是复杂的热图、3D图表,matplotlib都能轻松实现。本文将从基础概念→核心绘图函数→自定义美化→实战案例,手把手带你掌握matplotlib,让你的数据"说话"更直观。
一、什么是matplotlib?为什么需要它?
matplotlib是Python的一个2D绘图库,诞生于2003年,设计初衷是"让Python拥有像MATLAB一样的绘图能力"。它支持几乎所有常见的图表类型,且高度可定制------从颜色、字体到坐标轴刻度,都能精细调整。
为什么matplotlib是数据可视化首选?
- 功能全面:支持折线图、散点图、柱状图、直方图、饼图、热图等数十种图表;
- 高度定制:从全局样式到局部细节(如点的大小、线的粗细),均可灵活调整;
- 兼容性强:与NumPy、Pandas无缝配合(可直接传入数组或DataFrame绘图);
- 输出多样:可保存为PNG、PDF、SVG等多种格式,适配报告、论文、网页等场景。
举个例子:用Pandas分析完一组销售数据后,只需一行代码调用plot()(底层基于matplotlib),就能生成趋势图,直观发现数据规律。
二、安装与导入:5分钟准备工作
1. 安装matplotlib
matplotlib不是Python标准库,需用pip安装:
bash
pip install matplotlib # 基础安装,支持所有核心功能
2. 导入matplotlib
惯例将matplotlib.pyplot简写为plt(行业通用约定,简化代码):
python
import matplotlib.pyplot as plt # 导入绘图核心模块
import numpy as np # 配合生成示例数据
三、核心概念:Figure与Axes(画布与子图)
matplotlib的绘图逻辑基于两个核心对象:Figure(画布) 和Axes(子图/轴),理解它们是用好matplotlib的关键。
- Figure:整个绘图区域的"画布",可以看作一个窗口或页面,所有图表都绘制在Figure上。
- Axes:画布上的"子图",一个Figure可以包含多个Axes(比如一行两列的图表有2个Axes)。每个Axes有自己的坐标轴(x轴、y轴)、标题、图例等。

(图片来源:matplotlib官方文档)
快速创建画布与子图
python
# 方法1:先创建画布,再添加子图
fig = plt.figure(figsize=(8, 4)) # 创建画布,指定大小(宽8英寸,高4英寸)
ax = fig.add_subplot(1, 1, 1) # 添加1行1列的第1个子图(整个画布仅1个图)
# 方法2:同时创建画布和子图(推荐,更简洁)
fig, ax = plt.subplots(figsize=(8, 4)) # 等价于上面的代码
# 绘图:在子图上画一条线
ax.plot([1, 2, 3, 4], [1, 4, 9, 16]) # x=[1,2,3,4], y=[1,4,9,16]
# 显示图表(必须调用,否则不显示)
plt.show()
四、基础图表绘制:从简单到复杂
matplotlib支持数十种图表,以下是最常用的5种,覆盖80%的可视化场景。
1. 折线图(plot):展示趋势变化
折线图适合展示数据随时间或有序变量的变化趋势(如股票价格、温度变化)。
python
# 生成示例数据(x:时间,y:数值)
x = np.linspace(0, 10, 100) # 0到10的100个均匀点
y1 = np.sin(x) # 正弦曲线
y2 = np.cos(x) # 余弦曲线
# 创建画布和子图
fig, ax = plt.subplots(figsize=(10, 5))
# 绘制折线图
ax.plot(x, y1, label="sin(x)", color="blue", linewidth=2, linestyle="-") # 实线
ax.plot(x, y2, label="cos(x)", color="red", linewidth=1.5, linestyle="--") # 虚线
# 添加标题和标签
ax.set_title("正弦函数与余弦函数曲线", fontsize=15) # 标题
ax.set_xlabel("x值", fontsize=12) # x轴标签
ax.set_ylabel("y值", fontsize=12) # y轴标签
# 添加图例(显示label)
ax.legend(fontsize=10)
# 添加网格线(便于读数)
ax.grid(alpha=0.3) # alpha控制透明度
# 显示图表
plt.show()
关键参数说明:
label:图例名称(需配合ax.legend()显示);color:线的颜色(支持英文名称如"red"、十六进制如"#FF0000");linewidth:线的粗细;linestyle:线的样式("-"实线、"--"虚线、":"点线等)。
2. 散点图(scatter):展示变量关系
散点图用于观察两个变量之间的相关性(如身高与体重、学习时间与成绩)。
python
# 生成示例数据(100个随机点)
np.random.seed(42) # 固定随机种子,结果可复现
x = np.random.randn(100) # 均值0、标准差1的随机数(x变量)
y = 2 * x + np.random.randn(100) * 0.5 # y与x近似线性相关,加噪声
# 创建画布和子图
fig, ax = plt.subplots(figsize=(8, 6))
# 绘制散点图
scatter = ax.scatter(
x, y,
c=y, # 点的颜色由y值决定(颜色映射)
cmap="viridis", # 颜色映射方案(内置多种,如"coolwarm"、"rainbow")
s=50, # 点的大小
alpha=0.7, # 透明度(0-1)
edgecolors="black" # 点的边缘颜色
)
# 添加颜色条(解释颜色含义)
cbar = plt.colorbar(scatter)
cbar.set_label("y值", fontsize=10)
# 添加标题和标签
ax.set_title("x与y的散点图(带颜色映射)", fontsize=15)
ax.set_xlabel("x变量", fontsize=12)
ax.set_ylabel("y变量", fontsize=12)
# 添加网格
ax.grid(alpha=0.3)
plt.show()
关键参数说明:
c:点的颜色(可传入数组,实现按值着色);cmap:颜色映射表(让颜色随值变化更有层次感);s:点的大小(可传入数组,实现不同点不同大小);alpha:透明度(避免点重叠时看不清)。
3. 柱状图(bar/barh):对比分类数据
柱状图用于对比不同类别的数值(如各产品销量、各班级平均分),bar是垂直柱状图,barh是水平柱状图。
python
# 示例数据(类别与数值)
categories = ["产品A", "产品B", "产品C", "产品D"]
values = [35, 52, 28, 41] # 销量
# 创建画布和子图
fig, ax = plt.subplots(figsize=(8, 5))
# 绘制垂直柱状图
ax.bar(
categories, values,
color=["#FF6B6B", "#4ECDC4", "#45B7D1", "#FFA07A"], # 每个柱子不同颜色
width=0.6, # 柱子宽度
edgecolor="black" # 柱子边缘颜色
)
# 在柱子顶部添加数值标签
for i, v in enumerate(values):
ax.text(i, v + 1, str(v), ha="center", fontsize=10) # ha="center"水平居中
# 添加标题和标签
ax.set_title("各产品季度销量对比", fontsize=15)
ax.set_xlabel("产品类别", fontsize=12)
ax.set_ylabel("销量(件)", fontsize=12)
# 设置y轴范围(让顶部标签不溢出)
ax.set_ylim(0, max(values) + 10)
plt.show()
水平柱状图(barh)示例:
python
# 只需将bar改为barh,x和y互换
ax.barh(categories, values) # 水平柱状图,类别在y轴,数值在x轴
4. 直方图(hist):展示数据分布
直方图用于展示单变量的分布情况(如身高分布、成绩分布),与柱状图的区别是:直方图的x轴是连续区间( bins ),展示"在某个区间内有多少数据"。
python
# 生成示例数据(1000个符合正态分布的随机数)
np.random.seed(42)
data = np.random.normal(loc=50, scale=10, size=1000) # 均值50,标准差10
# 创建画布和子图
fig, ax = plt.subplots(figsize=(10, 5))
# 绘制直方图
n, bins, patches = ax.hist(
data,
bins=20, # 区间数量(分20个桶)
density=True, # 是否归一化(显示概率密度)
color="#6495ED",
alpha=0.7,
edgecolor="black"
)
# 添加正态分布曲线(更直观展示分布)
from scipy.stats import norm # 需安装scipy:pip install scipy
mu, sigma = norm.fit(data) # 拟合均值和标准差
x = np.linspace(bins[0], bins[-1], 100)
ax.plot(x, norm.pdf(x, mu, sigma), "r--", linewidth=2) # 概率密度曲线
# 添加标题和标签
ax.set_title("数据分布直方图(正态分布)", fontsize=15)
ax.set_xlabel("数值", fontsize=12)
ax.set_ylabel("概率密度", fontsize=12)
ax.grid(alpha=0.3, axis="y") # 只显示y轴网格
plt.show()
关键参数说明:
bins:区间数量(值越大,分桶越细,细节越清晰但可能噪声多);density:若为True,y轴显示概率密度(总面积为1),否则显示频数。
5. 饼图(pie):展示占比关系
饼图用于展示各部分占总体的比例(如市场份额、投票结果),适合类别较少的场景(建议不超过5类,否则可读性差)。
python
# 示例数据(各部分占比)
labels = ["直接访问", "搜索引擎", "社交媒体", "广告推广"]
sizes = [30, 40, 20, 10] # 总和100
explode = [0, 0.1, 0, 0] # 突出显示第2部分(搜索引擎)
# 创建画布和子图
fig, ax = plt.subplots(figsize=(7, 7)) # 饼图建议用正方形画布(避免变形)
# 绘制饼图
ax.pie(
sizes,
explode=explode, # 部分扇形偏离中心
labels=labels, # 类别标签
autopct="%1.1f%%", # 显示百分比(保留1位小数)
shadow=True, # 添加阴影(增强立体感)
startangle=90, # 起始角度(90度为从正上方开始)
colors=["#FF9999", "#66B2FF", "#99FF99", "#FFCC99"]
)
# 保证饼图是正圆形(否则可能椭圆)
ax.axis("equal")
# 添加标题
ax.set_title("网站访问来源占比", fontsize=15)
plt.show()
关键参数说明:
explode:控制各扇形是否偏离中心(突出重要部分);autopct:格式化百分比显示(如"%d%%"整数百分比);startangle:起始角度(0度从x轴正方向开始,90度从y轴正方向开始)。
五、自定义图表:让你的图更"专业"
默认图表往往不够美观,matplotlib支持从字体、颜色到坐标轴的全方位定制,以下是核心技巧。
1. 解决中文显示问题(关键!)
matplotlib默认不支持中文字体,直接显示中文会变成方框或乱码,需手动设置字体:
python
# 方法1:全局设置(一次设置,所有图表生效)
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"] # 支持中文的字体
plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题
# 方法2:局部设置(仅当前图表生效,更灵活)
fig, ax = plt.subplots()
ax.set_title("中文标题", fontproperties="SimHei", fontsize=15) # 指定字体
常用中文字体:
- SimHei(黑体,Windows系统);
- WenQuanYi Micro Hei(文泉驿微米黑,Linux系统);
- Heiti TC(黑体,Mac系统)。
2. 调整坐标轴范围与刻度
python
x = np.linspace(0, 10, 100)
y = np.sin(x)
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(x, y)
# 设置坐标轴范围
ax.set_xlim(2, 8) # x轴只显示2到8
ax.set_ylim(-1.2, 1.2) # y轴范围扩大,避免线条贴边
# 自定义刻度(替换默认刻度)
ax.set_xticks([2, 4, 6, 8]) # x轴显示的刻度点
ax.set_xticklabels(["2π/5", "4π/5", "6π/5", "8π/5"], rotation=30) # 刻度标签(旋转30度避免重叠)
ax.set_yticks([-1, 0, 1]) # y轴刻度点
plt.show()
3. 保存图表(高清无水印)
用plt.savefig()保存图表,建议用dpi参数提高分辨率(默认100,300适合印刷):
python
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [4, 5, 1])
ax.set_title("示例图表")
# 保存为PNG(高清)
plt.savefig("my_plot.png", dpi=300, bbox_inches="tight") # bbox_inches="tight"去除多余空白
# 也可保存为PDF(矢量图,放大不失真)
# plt.savefig("my_plot.pdf", bbox_inches="tight")
plt.show() # 注意:savefig必须在show()之前,否则保存空白图!
六、多子图布局:对比多个图表
当需要同时展示多个相关图表(如不同产品的销量趋势),可使用子图布局。
1. 规则网格布局(subplots)
用plt.subplots(nrows, ncols)创建n行n列的子图网格:
python
# 创建2行2列的子图(共4个子图)
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(12, 10)) # axes是子图数组
# 第1行第1列子图(折线图)
x = np.linspace(0, 10, 100)
axes[0, 0].plot(x, np.sin(x))
axes[0, 0].set_title("正弦曲线")
# 第1行第2列子图(散点图)
np.random.seed(42)
axes[0, 1].scatter(np.random.randn(50), np.random.randn(50))
axes[0, 1].set_title("随机散点")
# 第2行第1列子图(柱状图)
axes[1, 0].bar(["A", "B", "C"], [3, 7, 2])
axes[1, 0].set_title("柱状图示例")
# 第2行第2列子图(饼图)
axes[1, 1].pie([15, 30, 45, 10], labels=["a", "b", "c", "d"])
axes[1, 1].set_title("饼图示例")
axes[1, 1].axis("equal") # 饼图正圆
# 调整子图间距(避免标题/标签重叠)
plt.tight_layout() # 自动调整间距
# 也可手动调整:plt.subplots_adjust(wspace=0.3, hspace=0.5) # 水平/垂直间距
plt.show()
2. 不规则布局(gridspec)
对于非均匀分布的子图(如一个大图+几个小图),用plt.GridSpec更灵活:
python
# 创建2行2列的网格,但第1行合并为1个大图
gs = plt.GridSpec(2, 2, figure=plt.figure(figsize=(12, 8)))
# 第1行:合并两列(大图)
ax1 = plt.subplot(gs[0, :]) # 第0行,所有列
ax1.plot(np.linspace(0, 10, 100), np.sin(np.linspace(0, 10, 100)))
ax1.set_title("大图:正弦曲线")
# 第2行第1列(小图1)
ax2 = plt.subplot(gs[1, 0])
ax2.hist(np.random.randn(1000), bins=20)
ax2.set_title("小图1:直方图")
# 第2行第2列(小图2)
ax3 = plt.subplot(gs[1, 1])
ax3.pie([30, 70], labels=["男", "女"])
ax3.set_title("小图2:饼图")
ax3.axis("equal")
plt.tight_layout()
plt.show()
七、实战案例:鸢尾花数据集可视化
用经典的鸢尾花数据集(包含3类鸢尾花的4个特征),展示matplotlib的综合应用:
python
import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import load_iris # 从sklearn加载数据集
# 1. 加载数据
iris = load_iris()
X = iris.data # 特征数据(4列:花萼长度、花萼宽度、花瓣长度、花瓣宽度)
y = iris.target # 标签(0、1、2对应3类鸢尾花)
feature_names = iris.feature_names # 特征名称
# 2. 设置中文显示
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei"]
plt.rcParams["axes.unicode_minus"] = False
# 3. 创建4个子图(2x2),展示特征两两关系
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes = axes.flatten() # 转为1D数组,便于循环
# 特征对(0-1, 0-2, 0-3, 1-2)
pairs = [(0, 1), (0, 2), (0, 3), (1, 2)]
for i, (x_idx, y_idx) in enumerate(pairs):
# 绘制散点图(按类别着色)
for target, color in zip([0, 1, 2], ["r", "g", "b"]):
mask = (y == target)
axes[i].scatter(
X[mask, x_idx], X[mask, y_idx],
c=color, label=iris.target_names[target],
alpha=0.7
)
# 设置标题和标签
axes[i].set_title(f"{feature_names[x_idx]} vs {feature_names[y_idx]}")
axes[i].set_xlabel(feature_names[x_idx])
axes[i].set_ylabel(feature_names[y_idx])
axes[i].legend()
plt.tight_layout()
plt.show()
可视化效果:4个子图分别展示了鸢尾花不同特征之间的关系,通过颜色区分类别,可直观发现"花瓣长度"和"花瓣宽度"能很好地区分三类鸢尾花------这也是后续机器学习分类的重要依据。
八、避坑指南:matplotlib常见错误及解决
1. 中文显示为方框/乱码
问题 :图表中中文变成方框或乱码。
解决:设置支持中文的字体(见前文"解决中文显示问题")。
2. 保存的图片是空白
问题 :plt.savefig()保存的图片是空白。
原因 :savefig()在plt.show()之后调用,show()会清空画布。
解决 :先调用savefig(),再调用show():
python
plt.plot([1, 2, 3])
plt.savefig("plot.png") # 先保存
plt.show() # 再显示
3. 子图标题/标签重叠
问题 :多个子图的标题、坐标轴标签重叠。
解决 :用plt.tight_layout()自动调整间距,或plt.subplots_adjust(wspace=0.3, hspace=0.5)手动调整。
4. 饼图显示为椭圆
问题 :饼图看起来是椭圆而非正圆。
解决 :添加ax.axis("equal")保证x轴和y轴比例一致。
5. 图表大小不合适
问题 :图表太小或太大,元素显示不全。
解决 :创建画布时用figsize=(宽, 高)指定大小(单位为英寸),如plt.subplots(figsize=(10, 6))。
九、总结:matplotlib是数据可视化的基石
matplotlib的核心价值在于**"灵活可控"**------从最简单的折线图到复杂的多子图组合,从默认样式到高度定制化的出版级图表,它都能满足需求。掌握matplotlib后,你可以:
- 快速探索数据规律(通过散点图看相关性、直方图看分布);
- 清晰呈现分析结果(用柱状图对比、折线图展示趋势);
- 生成论文、报告所需的高清图表(支持矢量格式,放大不失真)。
学习建议:
- 先模仿再创新 :从官方示例(matplotlib示例库)开始,修改参数理解其作用;
- 结合实际数据练习:用自己的数据集(如CSV文件)绘制不同图表,对比哪种最能体现数据特点;
- 善用样式预设 :matplotlib提供多种预设样式(如
plt.style.use("seaborn-v0_8")),可快速美化图表; - 进阶学习seaborn:seaborn是基于matplotlib的高级库,代码更简洁,默认样式更美观,学会matplotlib后可快速上手。
数据可视化的核心是"清晰传达信息",工具是手段而非目的。选择合适的图表类型,配合简洁的样式,才能让你的数据故事更有说服力。