Matplotlib 的坐标系统非常灵活,主要涉及以下几个核心概念:

- 数据坐标:你传入
plot(),scatter(),text()等函数的原始 X, Y 值。 - 轴坐标:一个 0 到 1 的范围,(0, 0) 是轴的左下角,(1, 1) 是轴的右上角。
- 图形坐标:也是一个 0 到 1 的范围,但它是相对于整个图形窗口的,(0, 0) 是图形的左下角,(1, 1) 是图形的右上角。
- 变换对象:用于在不同坐标系统之间进行转换的桥梁。
下面我们详细分解这些概念,并通过代码示例来演示。
数据坐标
这是最直观、最常用的坐标系统,当你绘制数据时,你使用的就是数据坐标。
特点:
- 由你的数据决定范围。
- X 轴和 Y 轴的刻度是根据数据范围自动生成的。
- 这是你绘制图表内容(线、点、柱状图等)时默认使用的坐标系统。
示例:
我们绘制一个简单的正弦波,图上的点 (0, 0), (π/2, 1), (π, 0) 等就是数据坐标。

import numpy as np
import matplotlib.pyplot as plt
# 准备数据
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x)
# 创建图形和轴
fig, ax = plt.subplots()
# 使用数据坐标绘图
ax.plot(x, y)
# 在数据坐标 (π/2, 0.5) 处添加一个点
ax.plot(np.pi/2, 0.5, 'ro') # 'ro' 表示红色圆点
# 在数据坐标 (π, 0) 处添加文本
ax.text(np.pi, 0, 'Peak at (π, 0)', ha='center') # ha='center' 表示文本水平居中
和标签
ax.set_title("Data Coordinates Example")
ax.set_xlabel("X-axis (data)")
ax.set_ylabel("Y-axis (data)")
plt.show()
输出:
你会看到一个正弦波,在 x=π/2, y=0.5 的位置有一个红点,在 x=π, y=0 的位置有文字标签,这些元素的位置都是由 plot() 和 text() 函数中的原始数据值决定的。
轴坐标
当你想在当前坐标轴的特定位置(图例、注释)放置元素时,轴坐标非常有用,它将整个轴(包括刻度标签)视为一个单位矩形。
特点:
- 范围是
[0, 1]。 (0, 0)是轴的左下角(内部)。(1, 1)是轴的右上角(内部)。- 主要用于放置图例、注释文本等辅助元素。
如何使用:
在 text(), annotate(), legend() 等函数中,使用 transform=ax.transAxes 参数来指定使用轴坐标。

示例: 我们在轴的右上角(0.95, 0.95)添加一个注释,在左下角(0.05, 0.05)添加一个文本。
import numpy as np
import matplotlib.pyplot as plt
# 准备数据
x = np.linspace(0, 10, 100)
y = x**2
fig, ax = plt.subplots()
ax.plot(x, y)
# 使用轴坐标
# ax.transAxes 表示使用当前轴的坐标系统
# (0.95, 0.95) 表示轴的95%宽度和95%高度的位置
# va='top', ha='right' 使文本的顶部和右部对准该点
ax.text(0.95, 0.95, 'Top-Right Corner of Axes',
transform=ax.transAxes,
va='top', ha='right',
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
# 在左下角添加文本
ax.text(0.05, 0.05, 'Bottom-Left Corner of Axes',
transform=ax.transAxes,
va='bottom', ha='left')
ax.set_title("Axes Coordinates Example")
ax.set_xlabel("X-axis")
ax.set_ylabel("Y-axis")
plt.show()
输出: 你会看到,无论坐标轴如何缩放,这两个文本标签始终固定在坐标轴区域的右上角和左下角。
图形坐标
图形坐标的范围也是 [0, 1],但它是相对于整个图形窗口的,而不是单个坐标轴。
特点:
- 范围是
[0, 1]。 (0, 0)是图形窗口的左下角。(1, 1)是图形窗口的右上角。- 当你想在图形的任意位置(多个轴之间的空白处)添加文本或图形时非常有用。
如何使用:
使用 transform=fig.transFigure 参数。
示例: 我们创建两个并排的子图,然后在图形的正中央(0.5, 0.5)添加一个标题。
import matplotlib.pyplot as plt
# 创建一个 1x2 的子图布局
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
# 在第一个子图上画图
ax1.plot([1, 2, 3], [4, 5, 6])
ax1.set_title("Axes 1")
# 在第二个子图上画图
ax2.scatter([1, 2, 3], [6, 5, 4])
ax2.set_title("Axes 2")
# 使用图形坐标在图形中央添加一个总标题
# (0.5, 0.95) 表示图形宽度50%,高度95%的位置
# va='top' 使文本底部对准该点,这样文本就会在点的上方
fig.text(0.5, 0.95, 'This is a Figure-Level Title',
ha='center', va='top',
fontsize=16, transform=fig.transFigure)
plt.tight_layout() # 自动调整子图参数,使之填充整个图像区域
plt.show()
输出: 你会看到两个并排的子图,一个总标题位于整个图形窗口的顶部中央,这个标题的位置不受任何子图的影响。
变换对象
变换对象是 Matplotlib 坐标系统的核心,它定义了如何将一种坐标系统中的点转换为另一种坐标系统中的点。
ax.transData: 从数据坐标到显示坐标的变换。ax.transAxes: 从轴坐标到显示坐标的变换。fig.transFigure: 从图形坐标到显示坐标的变换。ax.transData.inverted(): 反向变换,从显示坐标到数据坐标。
实用场景:获取鼠标点击位置的数据坐标
这是一个非常实用的技巧,可以让你通过鼠标交互来获取数据点的具体值。
import numpy as np
import matplotlib.pyplot as plt
# 准备数据
x = np.linspace(0, 2*np.pi, 500)
y = np.sin(x)
fig, ax = plt.subplots()
ax.plot(x, y)
# 定义一个鼠标点击事件处理函数
def onclick(event):
# 检查点击是否在轴上
if event.inaxes == ax:
# ax.transData.inverted() 将显示坐标(event.xdata, event.ydata)
# 转换回数据坐标
data_x, data_y = event.xdata, event.ydata
# 清除之前的注释(如果有的话)
for txt in ax.texts:
if hasattr(txt, '_is_click_annotation'):
txt.remove()
# 添加新的注释
ax.text(data_x, data_y, f'({data_x:.2f}, {data_y:.2f})',
color='red', ha='left', va='bottom')
# 给文本对象添加一个属性,方便下次识别
ax.texts[-1]._is_click_annotation = True
# 重绘图形
fig.canvas.draw_idle()
# 连接事件
fig.canvas.mpl_connect('button_press_event', onclick)
ax.set_title("Click on the plot to see data coordinates")
plt.show()
输出: 运行代码后,点击曲线上的任意一点,就会在该点旁边显示其对应的数据坐标(x, y)。
总结与对比
| 坐标系统 | 范围 | 原点 | 主要用途 | 如何使用 |
|---|---|---|---|---|
| 数据坐标 | 由数据决定 | 数据的最小值 | 绘制数据本身(线、点、柱等) | 默认,直接传入 x, y 值 |
| 轴坐标 | [0, 1] |
轴的左下角 | 在轴内部放置图例、注释 | transform=ax.transAxes |
| 图形坐标 | [0, 1] |
图形的左下角 | 在整个图形上放置标题、注释 | transform=fig.transFigure |
掌握这三种坐标系统以及它们之间的转换,将让你能够精确控制 Matplotlib 图表中每一个元素的位置,从而创建出专业、美观的可视化图表。
