在数据分析、科学计算以及机器学习实践中,数据往往不是先靠"计算结果"被理解,而是先靠"图形表现"被看懂。数字本身当然重要,但当数据规模增大、变量关系变复杂时,仅仅阅读一串数值,往往很难迅速把握整体特征。此时,图形就成为理解数据的重要工具。
例如,一组数据如果直接写成:
cs
[10, 15, 20, 18, 25]
我们只能大致知道它在变化,却不容易立刻感受到变化的趋势、波动的位置以及增长的快慢;但如果将它绘制成折线图,数据走势通常会立即变得清晰得多。也正因为如此,数据可视化几乎贯穿于数据分析的整个过程:在探索阶段帮助我们观察分布,在建模阶段帮助我们检验关系,在结果展示阶段帮助我们传达结论。
在 Python 生态中,Matplotlib 是最基础、也最重要的可视化库之一。许多更高级的可视化工具,本质上都与它存在直接或间接的联系。
一、Matplotlib 是什么
Matplotlib 是 Python 中用于绘制二维图形的通用可视化库。它支持折线图、散点图、柱状图、直方图、饼图等多种常见图形,也可以进一步扩展到更复杂的可视化任务。
它之所以被广泛使用,主要有几个原因。
第一,它覆盖了数据分析中最常见的绘图需求。无论是展示趋势、比较类别、观察分布,还是分析变量关系,Matplotlib 都能提供基础支持。
第二,它与 NumPy、Pandas 等科学计算库结合紧密。很多时候,我们并不是单独"为了画图而画图",而是在数组计算、表格处理、统计分析之后,顺势进入可视化阶段。Matplotlib 恰好位于这条工作链的末端,是分析结果的主要展示工具之一。
第三,它具有较强的可定制性。图中的线条、颜色、标签、刻度、图例、网格、尺寸、分辨率等,通常都可以调整。这使得它既适合教学演示,也适合科研绘图和工程输出。
安装:
nginx
pip install matplotlib
导入时最常见的写法是:
javascript
import matplotlib.pyplot as plt
这里的 pyplot 是 Matplotlib 中最常用的接口模块。它提供了一套类似 MATLAB 风格的状态式绘图方式,因此在入门阶段非常常见。不过,Matplotlib 并不仅仅只有这一种写法。要真正理解它,必须先弄清楚它的图形结构。
二、Matplotlib 的图形结构
学习 Matplotlib 时,最容易混淆的问题之一,是"图到底是什么"。很多初学者只记住了 plt.plot()、plt.show(),却没有真正理解一幅图由哪些对象构成。实际上,Matplotlib 的图形系统是有清晰层次的。
从整体上看,可以把它理解为:
Figure → Axes → 具体图形元素
1、Figure:整个图形对象
Figure 表示整个图形对象,可以把它理解为一张完整的画布。它是所有绘图内容的最外层容器。图像的尺寸、分辨率、整体布局等,通常都与 Figure 有关。
2、Axes:实际绘图的区域
Axes 表示一个具体的绘图区,也就是带有坐标系的区域。绝大多数绘图操作,实际上都发生在 Axes 上。折线、散点、柱子、标题、坐标轴标签、图例等,都通常依附于某个 Axes。
很多初学者会把 Axes 理解为"坐标轴",这并不准确。更合适的理解是:Axes 是一个完整的绘图区,其中包含横轴、纵轴以及这个区域中的各种图形元素。
3、图形元素:线条、文本、图例等
在 Axes 内部,还存在许多更具体的元素,例如:
• 折线
• 散点
• 柱形
• 标题
• 坐标轴标签
• 图例
• 网格线
这些是图中真正被看到的内容。从使用角度看,初学阶段只需要先把握 Figure 和 Axes 的关系即可,不必过早深入到底层对象体系。
4、直观理解
可以把 Matplotlib 的结构粗略理解为:
css
Figure(整个图形)└── Axes(一个绘图区) ├── 线条 ├── 文本 ├── 图例 └── 坐标轴
如果一张图中包含多个子图,那么一个 Figure 中就会包含多个 Axes。
三、最基本的绘图流程
无论绘制什么类型的图形,Matplotlib 的基本过程大致都可以归纳为以下几步:
1、准备数据
2、创建图形对象或绘图区
3、调用绘图函数
4、添加标题、标签、图例、网格等辅助信息
5、显示图形或保存图像
例如,下面是一段最基础的绘图代码:
javascript
import matplotlib.pyplot as pltimport numpy as np
x = np.arange(0, 10)y = x ** 2
plt.plot(x, y)plt.show()

这段代码虽然很短,但已经包含了最核心的动作:
• x 和 y 是数据
• plt.plot(x, y) 用于绘制图形
• plt.show() 用于显示图形
不过,这样得到的图通常还比较"原始"。在实际使用中,我们往往还需要进一步补充说明信息。例如:
python
import matplotlib.pyplot as pltimport numpy as np
x = np.arange(0, 10)y = x ** 2
plt.plot(x, y, marker="o", label="y = x^2")plt.title("Example Function")plt.xlabel("x")plt.ylabel("y")plt.legend()plt.grid(True)plt.show()

这时图形就更完整了,因为它不仅有数据曲线,还有标题、坐标轴标签、图例和网格。对于读者来说,图形的可读性会明显提高。
四、最常见的几类基础图形
Matplotlib 支持的图形类型很多,但在入门阶段,应先掌握最常见、最有代表性的几类。它们分别对应不同的数据表达任务。

1、折线图:观察趋势
折线图是最常见的基础图形之一,适合展示数据随某个变量的变化趋势。例如时间序列、训练轮次、函数曲线等,都常常使用折线图。
示例:
python
import matplotlib.pyplot as pltimport numpy as np
x = np.linspace(0, 10, 100)y = np.sin(x)
plt.plot(x, y, label="sin(x)")plt.title("Line Plot")plt.xlabel("x")plt.ylabel("y")plt.legend()plt.grid(True)plt.show()
折线图强调的是"连续变化"。如果我们关心的是走势、波动、上升下降趋势,那么它通常是首选。
2、散点图:观察变量关系
散点图适合展示两个变量之间的关系。每一个点对应一组观测值,点的分布形态可以帮助我们初步判断相关性、聚集趋势或异常值。
示例:
python
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]y = [5, 7, 6, 8, 7]
plt.scatter(x, y)plt.title("Scatter Plot")plt.xlabel("x")plt.ylabel("y")plt.grid(True)plt.show()
如果折线图强调"连起来看变化",那么散点图更强调"分布在哪里、关系怎样"。在回归分析、相关分析和实验观察中,散点图都很常见。
3、柱状图:比较类别大小
柱状图适合比较不同类别的数据大小。例如不同班级人数、不同商品销量、不同模型准确率等,往往都可以用柱状图呈现。
示例:
javascript
import matplotlib.pyplot as plt
categories = ["A", "B", "C", "D"]values = [18, 24, 15, 27]
plt.bar(categories, values)plt.title("Bar Chart")plt.xlabel("Category")plt.ylabel("Value")plt.show()
柱状图强调的是"类别间比较"。它不是为了展示连续变化,而是为了直观比较不同项目之间的差异。
4、直方图:观察数据分布
直方图与柱状图外观相似,但含义不同。它不是用来比较离散类别,而是用来统计数据在各个区间中的分布情况。
示例:
kotlin
import matplotlib.pyplot as pltimport numpy as np
data = np.random.normal(0, 1, 1000)
plt.hist(data, bins=30)plt.title("Histogram")plt.xlabel("Value")plt.ylabel("Frequency")plt.show()
直方图常用于回答这些问题:
• 数据主要集中在哪些范围
• 数据分布是否对称
• 是否接近正态分布
• 是否存在明显偏态或异常集中现象
因此,在统计分析和机器学习的数据探索阶段,直方图尤其常见。
5、饼图:展示整体中的占比
饼图适合展示各部分在整体中的比例关系。
示例:
javascript
import matplotlib.pyplot as plt
sizes = [30, 40, 30]labels = ["A", "B", "C"]
plt.pie(sizes, labels=labels, autopct="%1.1f%%")plt.title("Pie Chart")plt.show()
饼图虽然直观,却并不总是最优选择。当类别较多或各部分差异不明显时,饼图的可读性会明显下降,这时柱状图往往更清晰。因此,饼图适合在类别不多、比例关系明确时使用。
五、状态式绘图与面向对象绘图
所谓"状态式绘图",可以理解为:当前有一个默认的图形环境,pyplot 会把你的操作自动作用到当前图或当前绘图区上。这种方式依赖的是 pyplot 提供的状态式接口,优点是上手快,代码短,适合简单场景。
比如:
css
plt.plot(x, y)plt.title("Example")plt.xlabel("x")plt.ylabel("y")plt.show()
但当图形变复杂时,它也容易让人分不清"当前到底在操作哪一个图、哪一个子图"。
因此,Matplotlib 官方更推荐另一种方式:面向对象绘图。
1、面向对象写法的基本形式
示例:
python
import matplotlib.pyplot as pltimport numpy as np
x = np.linspace(0, 10, 100)y = np.sin(x)
fig, ax = plt.subplots()ax.plot(x, y)ax.set_title("sin(x)")ax.set_xlabel("x")ax.set_ylabel("y")ax.grid(True)
plt.show()
说明:
• fig 表示整个图形对象
• ax 表示具体绘图区
也就是说,图是先被创建出来的,然后再明确地在某个 ax 上绘制内容。
2、为什么更推荐面向对象方式
面向对象写法的最大优点,是结构清楚。尤其当一张图中包含多个子图时,这种优势会更加明显。
示例:
apache
import matplotlib.pyplot as pltimport numpy as np
x = np.linspace(0, 10, 100)
fig, ax = plt.subplots(1, 2, figsize=(8, 4))
ax[0].plot(x, np.sin(x))ax[0].set_title("sin(x)")
ax[1].plot(x, np.cos(x))ax[1].set_title("cos(x)")
plt.tight_layout()plt.show()

这里的两个子图各自对应一个 Axes 对象。因为每个图都明确属于自己的 ax,所以代码更容易维护,也更不容易混乱。
3、如何理解两种方式的关系
初学时,可以先用状态式写法快速熟悉绘图流程;但随着图形复杂度提高,应逐步过渡到面向对象写法。
从本质上说:
• plt.plot() 是在"当前 Axes 上画图"
• ax.plot() 是在"指定 Axes 上画图"
前者强调方便,后者强调清晰。
六、图形修饰:让图真正可读
一张图并不是画出来就结束了。真正有用的图,通常还需要经过修饰,才能成为清晰的信息表达工具。
最常见的修饰包括以下几类。
1、标题
标题告诉读者这张图在展示什么内容。没有标题的图,往往需要读者自行猜测含义。
javascript
plt.title("Example Function")
或在面向对象写法中:
javascript
ax.set_title("Example Function")
2、坐标轴标签
横轴和纵轴标签用于说明变量含义。如果坐标轴没有标签,读者常常不知道横纵轴分别代表什么。
javascript
plt.xlabel("x")plt.ylabel("y")
对应的面向对象写法为:
javascript
ax.set_xlabel("x")ax.set_ylabel("y")
3、图例
当图中有多条曲线或多个图形对象时,图例非常重要。它用于说明不同颜色、不同线条分别对应什么含义。
apache
plt.plot(x, x, label="A")plt.plot(x, x**2, label="B")plt.legend()
4、网格
网格不是必须的,但在很多图中,它可以帮助读者更容易估计位置和数值范围,特别是在教学、分析和报告场景中很有帮助。
python
plt.grid(True)
5、子图间距调整
当一个 Figure 中有多个子图时,标题、标签和刻度文字可能互相挤压。此时通常需要调整布局。
go
plt.tight_layout()
它的作用是自动优化子图之间的间距,减少重叠问题。
七、图形显示、保存与输出后端
绘图完成后,通常还需要处理两个问题:一是怎样显示图形,二是怎样保存图像。
1、显示图形
go
plt.show()
在普通 Python 脚本中,通常需要显式调用 show(),图形窗口才会弹出。
在某些交互式环境中,图形可能会自动显示,但理解 show() 的作用仍然很重要。
2、保存图像
apache
plt.savefig("plot.png", dpi=300, bbox_inches="tight")
这里:
• "plot.png" 是输出文件名
• dpi=300 表示较高分辨率
• bbox_inches="tight" 表示尽量裁剪多余空白
一般来说,常见输出格式包括 PNG、PDF、SVG 等。
其中,PNG 适合普通图像输出,PDF 和 SVG 更适合高质量文档或矢量图场景。
在实际使用中,通常建议先保存,再显示。因为在某些环境中,如果先调用 show(),再调用 savefig(),可能会得到空白图像。
示例:
javascript
import matplotlib.pyplot as pltimport numpy as np
x = np.arange(5)y = x ** 2
plt.plot(x, y)plt.savefig("plot.png", dpi=300, bbox_inches="tight")plt.show()
3、输出后端
在 Matplotlib 中,图形之所以能够显示在屏幕上,或保存为 PNG、PDF、SVG 等文件,背后都依赖于后端(backend)。可以把后端简单理解为:图形最终通过什么方式被显示或输出。
输出后端常分为两种:
• 交互式后端主要用于在窗口、浏览器或 Notebook 中显示图形
• 非交互式后端主要用于生成图片文件或文档图形,而不强调界面交互
大多数情况下,Matplotlib 会自动选择合适的后端,因此不需要手动设置。
如果想查看当前 Matplotlib 使用的后端,可以写:
java
import matplotlib
print(matplotlib.get_backend())
如果确实需要手动设置后端,可以写:
javascript
import matplotlib
matplotlib.use("Agg")
说明:
"Agg" 表示基于 Anti-Grain Geometry 渲染引擎的非交互式后端,主要用于生成高质量的位图图像文件,如 PNG。
八、中文显示与简单全局配置
在中文环境下,Matplotlib 的一个常见问题是:图中中文可能无法正常显示,或者负号显示异常。这并不是绘图函数本身的问题,而通常与默认字体配置有关。
一种常见处理方式是使用 rcParams 设置全局参数:
python
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["SimHei"]plt.rcParams["axes.unicode_minus"] = False
这里:
• font.sans-serif 用于指定无衬线字体列表
• axes.unicode_minus = False 用于避免负号显示异常
这类设置属于全局默认配置,会影响后续创建的图形。
除了字体外,还可以通过 rcParams 调整默认图像尺寸、分辨率、线宽等内容。例如:
apache
plt.rcParams["figure.figsize"] = (6, 4)plt.rcParams["figure.dpi"] = 120
一般从说,不必一次记住太多全局参数。只需知道:Matplotlib 不仅可以"在单张图上修改",也可以通过全局配置改变后续图形的默认行为。
九、综合示例
下面给出一个简单的综合示例,将图形创建、绘图、修饰与输出串联起来。
apache
import matplotlib.pyplot as pltimport numpy as np
# 设置全局参数plt.rcParams["figure.figsize"] = (6, 4)plt.rcParams["figure.dpi"] = 120
# 准备数据x = np.linspace(0, 10, 100)y = np.sin(x)
# 创建图形fig, ax = plt.subplots()
# 绘图ax.plot(x, y, color="blue", label="sin(x)")
# 修饰图形ax.set_title("Sine Curve")ax.set_xlabel("x")ax.set_ylabel("y")ax.legend()ax.grid(True)
# 调整布局并保存plt.tight_layout()plt.savefig("sine_curve.png", dpi=300, bbox_inches="tight")plt.show()
📘 小结
Matplotlib 是 Python 中最基础的数据可视化库。学习它的关键,不只是会调用 plot()、scatter()、bar() 这样的函数,更重要的是理解 Figure 与 Axes 的结构关系,以及"准备数据---创建图形---绘制内容---修饰图形---显示或保存"的基本流程。当这条主线建立起来之后,后续无论是学习更复杂的绘图函数,还是处理多子图、样式配置与图像输出,都会更自然、更稳固。
延伸阅读:

"点赞有美意,赞赏是鼓励"