Matplotlib入门教程
简介¶
Matplotlib 是Python最强大的数据可视化库,可以创建高质量的2D/3D图形,完美支持科学计算与数据分析。
安装与导入¶
安装¶
通过pip安装matplotlib
pip install matplotlib # 基础安装,支持所有核心功能
Requirement already satisfied: matplotlib in /Users/tinker/code/jupyter-lab/.venv/lib/python3.13/site-packages (3.10.7) Requirement already satisfied: contourpy>=1.0.1 in /Users/tinker/code/jupyter-lab/.venv/lib/python3.13/site-packages (from matplotlib) (1.3.3) Requirement already satisfied: cycler>=0.10 in /Users/tinker/code/jupyter-lab/.venv/lib/python3.13/site-packages (from matplotlib) (0.12.1) Requirement already satisfied: fonttools>=4.22.0 in /Users/tinker/code/jupyter-lab/.venv/lib/python3.13/site-packages (from matplotlib) (4.61.0) Requirement already satisfied: kiwisolver>=1.3.1 in /Users/tinker/code/jupyter-lab/.venv/lib/python3.13/site-packages (from matplotlib) (1.4.9) Requirement already satisfied: numpy>=1.23 in /Users/tinker/code/jupyter-lab/.venv/lib/python3.13/site-packages (from matplotlib) (2.3.5) Requirement already satisfied: packaging>=20.0 in /Users/tinker/code/jupyter-lab/.venv/lib/python3.13/site-packages (from matplotlib) (25.0) Requirement already satisfied: pillow>=8 in /Users/tinker/code/jupyter-lab/.venv/lib/python3.13/site-packages (from matplotlib) (12.0.0) Requirement already satisfied: pyparsing>=3 in /Users/tinker/code/jupyter-lab/.venv/lib/python3.13/site-packages (from matplotlib) (3.2.5) Requirement already satisfied: python-dateutil>=2.7 in /Users/tinker/code/jupyter-lab/.venv/lib/python3.13/site-packages (from matplotlib) (2.9.0.post0) Requirement already satisfied: six>=1.5 in /Users/tinker/code/jupyter-lab/.venv/lib/python3.13/site-packages (from python-dateutil>=2.7->matplotlib) (1.17.0) Note: you may need to restart the kernel to use updated packages.
导入¶
导入matplotlib
import matplotlib.pyplot as plt # 导入绘图核心模块, plt简称是通用约定
import numpy as np # 配合生成示例数据
设置中文字体¶
# 让matplotlib自动找一个能显示中文的字体
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS', 'PingFang SC', 'Heiti TC', 'Songti SC', 'STFangsong']
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
核心概念:Figure与Axes(画布与子图)¶
画布和子图的创建¶
fig = plt.figure() # 只有画布,没有子图,此时不会绘制任何内容出来
fig, ax = plt.subplots() # 只有一个子图的画布
fig, axs = plt.subplots(2, 2) # 拥有2x2的网格子图的画布
fig, axs = plt.subplot_mosaic([['left', 'right_top'],
['left', 'right_bottom']]) # 拥有左边一个,右边两个子图的画布
plt.show()
两种绘图模式¶
Matplotlib 有两种主要的绘图模式(或者说两种使用方式):
是的,Matplotlib 有两种主要的绘图模式(或者说两种使用方式):
脚本式(Scripting / Pyplot)模式(最常用)
- 也叫 状态机(state-machine)模式 或 MATLAB式接口
- 使用
matplotlib.pyplot模块(通常导入为plt) - 隐式管理当前的 Figure 和 Axes,所有绘图命令(如
plt.plot(),plt.title(),plt.xlabel())都自动作用在“当前”的图上 - 适合快速绘图、交互式环境(Jupyter Notebook、IPython)、教学和日常使用
import matplotlib.pyplot as plt import numpy as np x = np.linspace(0, 10, 100) plt.plot(x, np.sin(x)) # 自动创建figure和axes plt.plot(x, np.cos(x)) plt.title("这是一个标题") plt.show() # 或者在Jupyter里直接显示
面向对象(Object-Oriented,简称OO)模式(推荐用于复杂图形)
- 显式创建
Figure和Axes对象,手动管理它们 - 更灵活、可控性更高,适合做子图、复杂布局、封装成函数/类、制作可复用的绘图代码
- 在大型项目、生产级代码、发表论文的高质量图形中几乎都是用这种方式
import matplotlib.pyplot as plt import numpy as np fig, ax = plt.subplots() # 显式创建figure和axes # 或者 fig = plt.figure(); ax = fig.add_subplot(111) x = np.linspace(0, 10, 100) ax.plot(x, np.sin(x), label='sin') ax.plot(x, np.cos(x), label='cos') ax.set_title("这是一个标题") ax.set_xlabel("x") ax.set_ylabel("y") ax.legend() ax.grid(True) plt.show()
- 显式创建
Matplotlib 官方文档明确指出:
“对于简单的绘图,pyplot 接口已经足够;但是一旦你需要更多控制(比如多个子图、复杂的布局),请使用面向对象的接口。”
折线图(plot):展示趋势变化¶
折线图适合展示数据随时间或有序变量的变化趋势(如股票价格、温度变化)。
最简单的折线图示例¶
x = np.linspace(0, 10, 100) # 0到10的100个均匀点
y = x + 2
plt.plot(x,y)
x_int = np.arange(0, 11) # 0,1,2,...,10
y_int = x_int + 2
plt.plot(x_int, y_int, 'go', markersize=5, label='整数点')
plt.legend()
plt.show()
import matplotlib.pyplot as plt
import numpy as np
x_smooth = np.linspace(0, 10, 200) # 用来画平滑曲线
x_int = np.arange(0, 11) # 0到10的整数点
plt.plot(x_smooth, x_smooth**2, 'b-', label='y = x²') # 蓝色平滑曲线
plt.plot(x_int, x_int**2, 'go', markersize=8, label='整数点') # 红色圆点突出整数
plt.xlabel('x')
plt.ylabel('y')
plt.title('y = x²(突出整数点)')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
$y=x^2$的折线图¶
import matplotlib.pyplot as plt
import numpy as np
x_smooth = np.linspace(0, 10, 200) # 用来画平滑曲线
x_int = np.arange(0, 11) # 0到10的整数点
plt.plot(x_smooth, x_smooth**2, 'b-', label='y = x²') # 蓝色平滑曲线
plt.plot(x_int, x_int**2, 'go', markersize=8, label='整数点') # 绿色圆点突出整数
plt.xlabel('x轴')
plt.ylabel('y轴')
plt.title('y = x²')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
使用面向对象方式绘图¶
虽然大多数的plt函数都可以直接转换为ax的方法进行调用(例如plt.plot() → ax.plot(),plt.legend() → ax.legend()等),但是并不是所有的命令都能应用这种情况。特别是用于设置极值、标签和标题的函数都有一定的改变。下表列出了将 MATLAB 风格的函数转换为面向对象的方法的区别:
- plt.xlabel() → ax.set_xlabel()
- plt.ylabel() → ax.set_ylabel()
- plt.xlim() → ax.set_xlim()
- plt.ylim() → ax.set_ylim()
- plt.title() → ax.set_title()
坐标轴范围设置对应关系:
ax.set_aspect('equal') # 替代 plt.axis('equal')
ax.autoscale(tight=True) # 替代 plt.axis('tight')
# 生成示例数据(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()
在面向对象接口中,与其逐个调用上面的方法来设置属性,更常见的使用ax.set()方法来一次性设置所有的属性.
ax = plt.axes()
ax.plot(x, np.sin(x))
ax.grid(True,
color='gray', # 网格线颜色
linestyle='--', # 虚线(-- 或 : 或 -.)
linewidth=0.7, # 线条细一点
alpha=0.7) # 透明度,别太抢戏
ax.set(xlim=(0, 10), ylim=(-2, 2),
xlabel='x', ylabel='sin(x)',
title='A Simple Plot');
调整折线图:线条颜色和风格¶
通过指定color关键字参数可以调整颜色。如果没有指定颜色,Matplotlib 会在一组默认颜色值中循环使用来绘制每一条线条。
plt.plot(x, np.sin(x - 0), color='blue') # 通过颜色名称指定
plt.plot(x, np.sin(x - 1), color='g') # 通过颜色简写名称指定(rgbcmyk)
plt.plot(x, np.sin(x - 2), color='0.75') # 介于0-1之间的灰阶值
plt.plot(x, np.sin(x - 3), color='#FFDD44') # 16进制的RRGGBB值
plt.plot(x, np.sin(x - 4), color=(1.0,0.2,0.3)) # RGB元组的颜色值,每个值介于0-1
plt.plot(x, np.sin(x - 5), color='chartreuse'); # 能支持所有HTML颜色名称值
颜色类型有:
| 颜色标记 | 描述 |
|---|---|
| r | 红色 |
| g | 绿色 |
| b | 蓝色 |
| c | 青色 |
| m | 品红 |
| y | 黄色 |
| k | 黑色 |
| w | 白色 |
通过linestyle关键字参数可以指定线条的风格:
plt.plot(x, x + 0, linestyle='solid')
plt.plot(x, x + 1, linestyle='dashed')
plt.plot(x, x + 2, linestyle='dashdot')
plt.plot(x, x + 3, linestyle='dotted');
# 还可以用形象的符号代表线条风格
plt.plot(x, x + 4, linestyle='-') # 实线
plt.plot(x, x + 5, linestyle='--') # 虚线
plt.plot(x, x + 6, linestyle='-.') # 长短点虚线
plt.plot(x, x + 7, linestyle=':'); # 点线
线类型有:
| 线类型标记 | 描述 |
|---|---|
| - | 实线 |
| : | 虚线 |
| -- | 破折线 |
| -. | 点划线 |
linestyle和color参数能够合并成一个非关键字参数,传递给plt.plot()函数:
调整折线图:坐标轴范围¶
Matplotlib 会自动选择非常合适的坐标轴范围来绘制你的图像,但是有些情况下你也需要自己进行相关调整。使用plt.xlim()和plt.ylim()函数可以调整坐标轴的范围:
如果某些情况下你希望将坐标轴反向,你可以通过上面的函数实现,将参数顺序颠倒即可:
通过 plt.axis() 可以在一个函数调用中就完成 x 轴和 y 轴范围的设置,传递一个 [xmin, xmax, ymin, ymax] 的列表参数即可:
将坐标轴压缩到刚好足够绘制折线图像的大小:
还可以通过设置'equal'参数设置x轴与y轴使用相同的长度单位:
散点图(scatter):展示变量关系¶
散点图用于观察两个变量之间的相关性(如身高与体重、学习时间与成绩)。
最简单的散点图示例¶
import matplotlib.pyplot as plt
x = [160, 170, 180, 165, 175]
y = [60, 70, 80, 65, 75]
plt.scatter(x, y)
plt.title('散点图示例')
plt.xlabel('身高(cm)')
plt.ylabel('体重(kg)')
plt.grid()
### 使用 plt.plot 绘制散点图
设置散点的数据点符号(marker)¶
rng = np.random.RandomState(0)
for marker in ['o', '.', ',', 'x', '+', 'v', '^', '<', '>', 's', 'd']:
plt.plot(rng.rand(5), rng.rand(5), marker,
label="marker='{0}'".format(marker))
plt.legend(numpoints=1)
plt.xlim(0, 1.8);
数据点符号¶
在 Matplotlib 里,marker 就是“数据点符号”——用来在坐标位置画一个小图案,让人一眼看到“这里有一个数据点”。
官方文档的标准叫法也是 marker,没有别的术语。
分类速览(按形状/是否填充):
- 点形:
., - 线形:
|_ - 空形:
''None' ' - 几何填充:
os^v<>phHDd - 三叶草:
* - 十字:
+xX - 数学/特殊:数字 0–9、字母 (a–z, A–Z)、
$…$(LaTeX)、自定义路径(verts, 0)等。
所有可用 marker 列表就是 matplotlib.markers.MarkerStyle.markers 的键;字符串键(单字符或 TeX 符号串)就是它们的“标准名称”。
import matplotlib.pyplot as plt
import matplotlib.markers as mmarkers
import numpy as np
# 取到所有内置 marker
markers = list(mmarkers.MarkerStyle.markers.keys())
markers = [m for m in markers if isinstance(m, str)] # 只要单字符/字符串
markers.sort(key=lambda x: (str(x).lower(), len(str(x))))
# 每行 10 个
cols = 10
rows = (len(markers) + cols - 1) // cols
fig, ax = plt.subplots(figsize=(cols * 1.2, rows * 1.2))
ax.set_xlim(-0.5, cols - 0.5)
ax.set_ylim(-0.5, rows - 0.5)
ax.set_aspect('equal')
ax.axis('off')
for i, m in enumerate(markers):
row, col = divmod(i, cols)
filled = mmarkers.MarkerStyle(m).is_filled()
kwargs = dict(s=300, color='C0')
if filled:
kwargs['edgecolor'] = 'black'
# 用 scatter 画 marker
ax.scatter(col, rows - 1 - row, marker=m, **kwargs)
# 把 marker 名字写在格子下方
ax.text(col, rows - 1 - row - 0.25, repr(m), ha='center', va='top', fontsize=8)
fig.suptitle('Matplotlib Built-in Markers', fontsize=14)
plt.tight_layout()
plt.show()
自定义散点颜色
x = np.array([1, 2, 3, 4, 5, 6, 7, 8])
y = np.array([1, 4, 9, 16, 7, 11, 23, 18])
colors = np.array(["red","green","black","orange","purple","beige","cyan","magenta"])
plt.scatter(x, y, c=colors)
plt.show()
散点图分组
import matplotlib.pyplot as plt
import numpy as np
x = np.array([5,7,8,7,2,17,2,9,4,11,12,9,6])
y = np.array([99,86,87,88,111,86,103,87,94,78,77,85,86])
plt.scatter(x, y, color = 'hotpink')
x = np.array([2,2,8,1,15,8,12,9,7,3,11,4,7,14,12])
y = np.array([100,105,84,105,90,99,90,95,94,100,79,112,91,80,85])
plt.scatter(x, y, color = '#88c999')
plt.show()
随机颜色和大小的散点图
import numpy as np
import matplotlib.pyplot as plt
# 随机数生成器的种子
np.random.seed(19680801)
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = (30 * np.random.rand(N))**2 # 0 to 15 point radii
plt.scatter(x, y, s=area, c=colors, alpha=0.5) # 设置颜色及透明度
plt.title("RUNOOB Scatter Test") # 设置标题
plt.colorbar();
plt.show()
带颜色条的散点图
import matplotlib.pyplot as plt
import numpy as np
x = np.array([5,7,8,7,2,17,2,9,4,11,12,9,6])
y = np.array([99,86,87,88,111,86,103,87,94,78,77,85,86])
colors = np.array([0, 10, 20, 30, 40, 45, 50, 55, 60, 70, 80, 90, 100])
plt.scatter(x, y, c=colors, cmap='viridis')
plt.colorbar()
plt.show()
import matplotlib.pyplot as plt
import numpy as np
# 数据
x = np.random.rand(50)
y = np.random.rand(50)
colors = np.random.rand(50) # 用来控制颜色
area = (30 * np.random.rand(50))**2
plt.figure(figsize=(6, 4))
# 1. 画散点并返回 PathCollection
sc = plt.scatter(x, y, s=area, c=colors, cmap='viridis', alpha=0.8)
# 2. 加颜色条
plt.colorbar(sc, label='color value')
plt.title('Scatter with Colorbar')
plt.tight_layout()
plt.show()
# 生成示例数据(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()
柱状图(bar/barh):对比分类数据¶
柱状图用于对比不同类别的数值(如各产品销量、各班级平均分),bar是垂直柱状图,barh是水平柱状图。
import matplotlib.pyplot as plt
categories = ['A', 'B', 'C', 'D', 'E']
values = [25, 40, 60, 30, 50]
plt.bar(categories, values)
plt.title('柱状图示例')
plt.xlabel('类别')
plt.ylabel('值')
plt.show()
# 示例数据(类别与数值)
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)示例
直方图(hist):展示数据分布¶
直方图用于展示单变量的分布情况(如身高分布、成绩分布),与柱状图的区别是:直方图的x轴是连续区间( bins ),展示“在某个区间内有多少数据”。
# 生成示例数据(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()
饼图(pie):展示占比关系¶
饼图用于展示各部分占总体的比例(如市场份额、投票结果),适合类别较少的场景(建议不超过5类,否则可读性差)。
labels = ['A', 'B', 'C', 'D', 'E']
sizes = [15, 30, 25, 10, 20]
plt.pie(sizes, labels=labels, autopct='%1.1f%%')
plt.title('饼图示例')
plt.show()
# 示例数据(各部分占比)
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()
多子图¶
使用MATLAB式接口方式¶
import matplotlib.pyplot as plt
# 创建一个2x2的子图布局
plt.subplot(2, 2, 1)
plt.plot(x, y)
plt.subplot(2, 2, 2)
plt.scatter(x, y)
plt.subplot(2, 2, 3)
plt.bar(categories, values)
plt.subplot(2, 2, 4)
plt.pie(sizes, labels=labels, autopct='%1.1f%%')
plt.tight_layout() # 调整子图布局
plt.show()
使用面向对象模式¶
# 创建2行2列的子图(共4个子图)
fig, axes = plt.subplots(nrows=2, ncols=2) # 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()
参考资料¶
- 画出你的数据故事:Python中Matplotlib使用从基础到高级: https://cloud.tencent.com/developer/article/2318254
- Python matplotlib详解:从入门到精通,数据可视化利器 - 指南: https://www.cnblogs.com/clnchanpin/p/19278911
- 全文 40000 字,最全(最强) Matplotlib 实操指南: https://zhuanlan.zhihu.com/p/388287863
- matplotlib官网:https://matplotlib.org/stable/
