Matplotlib 教程:从入门到精通
Matplotlib 是 Python 最基础、最核心的数据可视化库,它功能强大,高度可定制,可以创建几乎所有你想要的静态、动态和交互式图表,它也是许多其他高级可视化库(如 Seaborn、Pandas Plot)的基础。

目录
-
- 什么是 Matplotlib?
- 安装与导入
- 理解 Matplotlib 的核心:三层结构
- 一个最简单的例子:
plt.plot() - 图表的组成元素
-
- 折线图
- 散点图
- 柱状图
- 直方图
- 饼图
- 箱形图
-
- 、坐标轴标签和图例
- 设置坐标轴范围和刻度
- 添加网格线
- 设置线条样式、颜色和标记
- 调整图形大小和分辨率
- 保存图表
- 中文显示问题
-
(图片来源网络,侵删)plt.subplots():创建子图plt.subplot():在网格中添加子图GridSpec:更灵活的子图布局
-
- 面向对象 API 与
pyplotAPI 的选择 - 使用
Axes对象进行精细控制 - 添加注释和箭头
- 绘制多组数据(双Y轴)
- 面向对象 API 与
-
- 案例1:绘制正弦和余弦函数
- 案例2:多组数据的对比柱状图
-
官方文档与学习资源
(图片来源网络,侵删)
第一部分:Matplotlib 基础
什么是 Matplotlib?
Matplotlib 是一个 Python 2D 绘图库,它可以在各种平台上以各种硬拷贝格式和交互式环境生成出具有出版品质级别的图形,它模仿了 MATLAB 的绘图接口,因此对于有 MATLAB 背景的用户来说非常友好。
安装与导入
如果你还没有安装 Matplotlib,可以通过 pip 进行安装:
pip install matplotlib
安装完成后,在你的 Python 脚本或 Jupyter Notebook 中导入它:
import matplotlib.pyplot as plt import numpy as np # 通常会用 NumPy 生成数据
plt 是 matplotlib.pyplot 的常用别名,np 是 numpy 的常用别名。
理解 Matplotlib 的核心:三层结构
理解 Matplotlib 的三层结构对于高级定制至关重要:
- 后端层:处理底层渲染细节,比如在哪个窗口显示图表,是保存为图片文件还是显示为交互式界面,通常我们不需要直接与这一层交互。
- 艺术家层:这是 Matplotlib 的核心,你看到的图表上的所有元素(线条、文本、图例、坐标轴等)都是一个
Artist对象,你可以通过创建和修改这些Artist对象来精确控制图表的每一个细节。 - 脚本层:这是我们最常接触的一层,它通过
pyplot模块提供了类似 MATLAB 的简单接口。pyplot会自动帮你处理创建Figure和Axes等底层Artist对象的工作,让你能快速绘图。
- 新手:主要使用脚本层 (
plt.plot()),简单快速。 - 进阶用户:主要使用艺术家层 (
ax.plot()),进行更精细的控制。
一个最简单的例子:plt.plot()
# 1. 准备数据 x = np.linspace(0, 10, 100) # 从0到10,生成100个点 y = np.sin(x) # 2. 绘制图形 plt.plot(x, y) # 3. 显示图形 plt.show()
运行这段代码,会弹出一个窗口显示一个标准的正弦曲线。
图表的组成元素
了解一个图表的基本组成部分,有助于你更好地理解如何定制它:
- Figure (画布):整个图表的窗口或页面,你可以把它想象成一个画板。
- Axes (坐标轴):一个
Figure可以包含多个Axes(子图),每个Axes都有自己的坐标系、标题、标签等,它是我们进行绘图操作的主要对象。 - Axis (坐标轴):指 X 轴 和 Y 轴,包括刻度和标签。
- Title (标题):整个图表的标题。
- Label (标签):X 轴和 Y 轴的名称。
- Legend (图例):用于说明图表中不同线条或元素的含义。
- Tick (刻度):坐标轴上的刻度标记。
- Grid (网格):背景中的网格线。
第二部分:常用图表绘制
Matplotlib 支持几乎所有常见的图表类型。
折线图
最常用的图表,用于展示数据随时间或有序类别的变化趋势。
x = np.arange(0, 5, 0.1)
y = x ** 2
plt.plot(x, y, label='y = x^2')"折线图示例")
plt.xlabel("X 轴")
plt.ylabel("Y 轴")
plt.legend() # 显示图例
plt.grid(True) # 显示网格
plt.show()
散点图
用于展示两个变量之间的关系。
# 生成随机数据
np.random.seed(0)
x = np.random.rand(50)
y = np.random.rand(50)
colors = np.random.rand(50)
sizes = 1000 * np.random.rand(50)
plt.scatter(x, y, c=colors, s=sizes, alpha=0.5, cmap='viridis')"散点图示例")
plt.xlabel("X 变量")
plt.ylabel("Y 变量")
plt.colorbar() # 显示颜色条
plt.show()
柱状图
用于比较不同类别之间的数据大小。
categories = ['A', 'B', 'C', 'D']
values = [15, 30, 45, 10]
plt.bar(categories, values, color=['red', 'blue', 'green', 'orange'])"柱状图示例")
plt.xlabel("类别")
plt.ylabel("数值")
plt.show()
直方图
用于展示数据的分布情况,显示数据落在各个区间的频率。
data = np.random.randn(1000) # 生成1000个标准正态分布的随机数
plt.hist(data, bins=30, color='skyblue', edgecolor='black')"直方图示例")
plt.xlabel("数值区间")
plt.ylabel("频数")
plt.show()
饼图
用于展示各部分占总体的比例。
sizes = [15, 30, 45, 10]
labels = ['A', 'B', 'C', 'D']
explode = (0, 0.1, 0, 0) # 突出显示第二块
plt.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',
shadow=True, startangle=90)"饼图示例")
plt.axis('equal') # 保证饼图是圆的
plt.show()
箱形图
用于展示一组数据的分布情况,包括中位数、四分位数和异常值。
data = [np.random.normal(0, std, 100) for std in range(1, 4)]
plt.boxplot(data, labels=['低方差', '中方差', '高方差'])"箱形图示例")
plt.ylabel("数值")
plt.show()
第三部分:图表定制与美化
、坐标轴标签和图例
plt.plot(x, np.sin(x), label='sin(x)')
plt.plot(x, np.cos(x), label='cos(x)')
"正弦和余弦函数", fontsize=16)
plt.xlabel("x (弧度)", fontsize=12)
plt.ylabel("f(x)", fontsize=12)
plt.legend(loc='upper right') # loc可以指定图例位置
设置坐标轴范围和刻度
plt.plot(x, np.sin(x)) # 设置坐标轴范围 plt.xlim([0, 5]) # x轴范围从0到5 plt.ylim([-1.5, 1.5]) # y轴范围从-1.5到1.5 # 设置刻度 plt.xticks(np.arange(0, 5.1, 1)) # x轴刻度为0, 1, 2, 3, 4, 5 plt.yticks([-1, 0, 1]) # y轴刻度为-1, 0, 1
添加网格线
plt.plot(x, np.sin(x)) plt.grid(True, linestyle='--', alpha=0.6) # 虚线,透明度0.6
设置线条样式、颜色和标记
# 颜色: 可以是颜色名称 (如 'red'), 缩写 (如 'r'), 或十六进制码 (如 '#FF0000') # 线条样式: '-' 实线, '--' 虚线, '-.' 点划线, ':' 点线 # 标记: 'o' 圆圈, 's' 方块, '^' 三角形, '+' 加号 plt.plot(x, np.sin(x), color='g', linestyle='--', marker='o', markersize=8, label='sin(x)') plt.plot(x, np.cos(x), color='#FF5733', linestyle='-', marker='s', markersize=5, label='cos(x)') plt.legend()
调整图形大小和分辨率
在绘图之前使用 plt.figure() 来设置。
# figsize=(宽度, 高度),单位是英寸 # dpi 是分辨率 (dots per inch) plt.figure(figsize=(10, 6), dpi=100) plt.plot(x, np.sin(x))"调整大小的图形") plt.show()
保存图表
使用 plt.savefig() 函数。
plt.figure(figsize=(8, 5))
plt.plot(x, np.sin(x))"保存的图表")
# 保存为 PNG 图片,dpi可以设置分辨率
plt.savefig('sine_wave.png', dpi=300, bbox_inches='tight')
# bbox_inches='tight' 可以防止标签被裁剪
# 也可以保存为 PDF, SVG 等矢量格式,无损缩放
# plt.savefig('sine_wave.pdf')
plt.show()
中文显示问题
Matplotlib 默认不支持中文字符,如果要在图表中显示中文,需要设置一个支持中文的字体。
全局设置
import matplotlib as mpl
# 设置全局字体为 SimHei (黑体),你也可以用 'Microsoft YaHei' 等
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 解决负号显示问题
mpl.rcParams['axes.unicode_minus'] = False
plt.plot(x, np.sin(x))"正弦函数")
plt.xlabel("x 轴")
plt.show()
使用 fontproperties 参数(推荐)
这种方法更灵活,只对当前生效。
plt.plot(x, np.sin(x))"正弦函数", fontproperties='SimHei')
plt.xlabel("x 轴", fontproperties='SimHei')
plt.show()
第四部分:多图与子图
你可以在一个 Figure 中绘制多个子图。
plt.subplots():创建子图
这是最推荐、最清晰的方法。
# 创建一个 2x1 的子图网格,共享 x 轴
fig, axes = plt.subplots(2, 1, sharex=True)
# axes 是一个包含所有子图 Axes 对象的 NumPy 数组
axes[0].plot(x, np.sin(x), 'r-')
axes[0].set_title('正弦波')
axes[0].set_ylabel('sin(x)')
axes[1].plot(x, np.cos(x), 'b-')
axes[1].set_title('余弦波')
axes[1].set_xlabel('x (弧度)')
axes[1].set_ylabel('cos(x)')
# 自动调整子图参数,使之填充整个图像区域
plt.tight_layout()
plt.show()
plt.subplot():在网格中添加子图
这种方法比较传统,适合动态添加子图。
plt.subplot(2, 1, 1) # 2行1列,第1个子图 plt.plot(x, np.sin(x))'正弦波') plt.subplot(2, 1, 2) # 2行1列,第2个子图 plt.plot(x, np.cos(x))'余弦波') plt.tight_layout() plt.show()
GridSpec:更灵活的子图布局
当你需要不规则的子图大小时,GridSpec 非常强大。
import matplotlib.gridspec as gridspec
fig = plt.figure(figsize=(10, 8))
gs = gridspec.GridSpec(2, 2, width_ratios=[2, 1], height_ratios=[1, 2])
# 第一个子图,占据第一行第一列,跨2列
ax1 = fig.add_subplot(gs[0, :])
ax1.plot(x, np.sin(x))
ax1.set_title('大图')
# 第二个子图,占据第二行第一列
ax2 = fig.add_subplot(gs[1, 0])
ax2.plot(x, np.cos(x))
ax2.set_title('子图 1')
# 第三个子图,占据第二行第二列
ax3 = fig.add_subplot(gs[1, 1])
ax3.plot(x, x**2)
ax3.set_title('子图 2')
plt.tight_layout()
plt.show()
第五部分:进阶概念
面向对象 API 与 pyplot API 的选择
pyplotAPI (过程式):plt.plot(),plt.title(),简单直接,适合快速绘图和简单图表。- 面向对象 API:
fig, ax = plt.subplots(),ax.plot(),ax.set_title(),更清晰、更强大,是构建复杂图表和自动化绘图的推荐方式。
强烈建议在编写正式代码时,优先使用面向对象的 API。
使用 Axes 对象进行精细控制
这是面向对象 API 的核心。Axes 对象拥有几乎所有的绘图和定制方法。
fig, ax = plt.subplots(figsize=(8, 5))
# 使用 ax 对象进行绘图
ax.plot(x, np.sin(x), color='blue', label='sin(x)')
ax.plot(x, np.cos(x), color='red', label='cos(x)')
# 使用 ax 对象设置属性
ax.set_title("使用 Axes 对象", fontsize=16)
ax.set_xlabel("X 轴", fontsize=12)
ax.set_ylabel("Y 轴", fontsize=12)
ax.legend()
ax.grid(True)
plt.show()
添加注释和箭头
使用 ax.annotate() 方法。
fig, ax = plt.subplots()
ax.plot(x, np.sin(x))
# 在 x=3pi/2 的点添加注释
ax.annotate('最大值',
xy=(3*np.pi/2, 1), # 箭头指向的坐标
xytext=(2*np.pi, 1.5), # 文本坐标
arrowprops=dict(facecolor='black', shrink=0.05),
fontsize=12)
plt.show()
绘制多组数据(双Y轴)
当两个数据集的量纲或数值范围差异很大时,可以使用双Y轴。
fig, ax1 = plt.subplots()
# 第一个Y轴
color = 'tab:red'
ax1.set_xlabel('时间 (s)')
ax1.set_ylabel('温度 (°C)', color=color)
ax1.plot(t, data1, color=color)
ax1.tick_params(axis='y', labelcolor=color)
# 创建第二个Y轴,共享X轴
ax2 = ax1.twinx()
color = 'tab:blue'
ax2.set_ylabel('湿度 (%)', color=color)
ax2.plot(t, data2, color=color)
ax2.tick_params(axis='y', labelcolor=color)
fig.tight_layout()
plt.show()
第六部分:实战案例
案例1:绘制正弦和余弦函数
目标:在一个图中绘制 sin(x) 和 cos(x),并添加标题、坐标轴标签、图例和网格线。
import numpy as np
import matplotlib.pyplot as plt
# 1. 准备数据
x = np.linspace(0, 2 * np.pi, 400)
y_sin = np.sin(x)
y_cos = np.cos(x)
# 2. 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))
# 3. 绘制曲线
ax.plot(x, y_sin, label='sin(x)', color='blue', linestyle='-')
ax.plot(x, y_cos, label='cos(x)', color='red', linestyle='--')
# 4. 添加图表元素
ax.set_title('正弦和余弦函数', fontsize=16)
ax.set_xlabel('x (弧度)', fontsize=12)
ax.set_ylabel('f(x)', fontsize=12)
ax.legend(loc='upper right')
ax.grid(True, linestyle=':', alpha=0.7)
# 5. 设置刻度
ax.set_xticks([0, np.pi/2, np.pi, 3*np.pi/2, 2*np.pi])
ax.set_xticklabels(['0', 'π/2', 'π', '3π/2', '2π'])
# 6. 显示和保存
plt.tight_layout()
plt.savefig('trig_functions.png')
plt.show()
案例2:多组数据的对比柱状图
目标:并排展示不同城市在不同季度的销售额。
import numpy as np
import matplotlib.pyplot as plt
# 1. 准备数据
cities = ['北京', '上海', '广州']
quarters = ['Q1', 'Q2', 'Q3', 'Q4']
beijing_sales = [120, 150, 180, 200]
shanghai_sales = [100, 170, 160, 190]
guangzhou_sales = [80, 140, 170, 210]
x = np.arange(len(quarters)) # x轴的位置
width = 0.25 # 柱状图的宽度
# 2. 创建图形和坐标轴
fig, ax = plt.subplots(figsize=(10, 6))
# 3. 绘制柱状图
bar1 = ax.bar(x - width, beijing_sales, width, label='北京')
bar2 = ax.bar(x, shanghai_sales, width, label='上海')
bar3 = ax.bar(x + width, guangzhou_sales, width, label='广州')
# 4. 添加图表元素
ax.set_title('各城市季度销售额对比', fontsize=16)
ax.set_ylabel('销售额 (万元)', fontsize=12)
ax.set_xticks(x)
ax.set_xticklabels(quarters)
ax.legend()
# 5. 在柱状图上添加数值标签
def add_labels(bars):
for bar in bars:
height = bar.get_height()
ax.annotate('{}'.format(height),
xy=(bar.get_x() + bar.get_width() / 2, height),
xytext=(0, 3), # 3 points vertical offset
textcoords="offset points",
ha='center', va='bottom')
add_labels(bar1)
add_labels(bar2)
add_labels(bar3)
# 6. 显示和保存
plt.tight_layout()
plt.savefig('sales_comparison.png')
plt.show()
第七部分:总结与资源
这份教程涵盖了 Matplotlib 的核心知识点:
- 基础:理解三层结构,掌握
pyplot快速绘图。 - 绘图:学会绘制折线、散点、柱状、直方图等常用图表。
- 定制:能够美化图表,设置标题、标签、颜色、样式等。
- 布局:掌握创建子图和复杂布局的技巧。
- 进阶:理解面向对象 API,能进行精细控制和添加高级元素。
熟能生巧,多练习,多看官方文档的示例,是掌握 Matplotlib 的最佳途径。
官方文档与学习资源
- Matplotlib 官方文档:最权威、最全面的资源,包含了所有函数的详细说明和海量示例。
- Matplotlib Gallery:官方的示例库,你可以在这里找到几乎所有你能想到的图表类型及其代码,是解决实际问题和学习高级技巧的宝库。
- Python Graph Gallery:一个非常好的第三方网站,提供了大量精美的图表示例和详细的 Python 代码实现,风格现代,非常实用。
- Jupyter Notebook:在 Jupyter Notebook 中使用 Matplotlib 是非常棒的学习和探索方式,可以即时看到绘图结果。
希望这份教程对你有帮助!祝你绘图愉快!
