Matplotlib 默认的刻度标志和格式被设计成能满足许多通用场景的需求,但是不会是所有图表的最佳选择。本节会介绍一些调整刻度位置和格式的例子来说明自定义刻度的使用。

在介绍例子之前,我们应该加深对 Matplotlib 图表的对象层次的理解。Matplotlib 的设计目标是展示在图表中的所有内容都会表达成为 Python 的对象:例如,回忆前面我们介绍过​​figure​​​指的是用来展示图表所有内容的方框。每个 Matplotlib 对象也被设计为其子对象的一个容器:例如​​figure​​​对象中可以包含一个或多个​​axes​​​对象,每个​​axes​​对象都依次包含着其他用来展示图表的内容对象。

刻度也不例外。每个​​axes​​​对象都有着属性​​xaxis​​​和​​yaxis​​,表示 x 和 y 轴,其中包含着所有的属性用来指代轴的线、刻度和标签。

主要的和次要的刻度

在每个坐标轴上,都有主要的刻度和次要的刻度概念。正如名字指代的,主要刻度通常是大的和更多用到的,而次要刻度通常是小的。默认 Matplotlib 很少使用次要刻度,但是在对数图表中我们可能会看到它们:

在 Matplotlib 2.0 之后,当 axis 的跨度过大时,默认次要刻度将会不再展示,因此,下面的代码经过了修改,加上了 xlim 和 ylim 参数。

import matplotlib.pyplot as plt
plt.style.use('classic')
import numpy as np
ax = plt.axes(xscale='log', yscale='log', xlim=[10e-5, 10e5], ylim=[10e-5, 10e5])
ax.grid();
plt.show()

Matplotlib基础--自定义刻度_图例

我们看到每个主要刻度显示了一个大的标志和标签,而每个次要刻度显示了一个小的刻度标志没有标签。

这些刻度属性,位置和标签,都可以使用每个轴的​​formatter​​​和​​locator​​对象进行个性化设置。下面我们来查看一下 x 轴的相应对象:

print(ax.xaxis.get_major_locator())
print(ax.xaxis.get_minor_locator())

<matplotlib.ticker.LogLocator object at 0x000001E8074AF108>
<matplotlib.ticker.LogLocator object at 0x000001E8074AD908>

print(ax.xaxis.get_major_formatter())
print(ax.xaxis.get_minor_formatter())

<matplotlib.ticker.LogFormatterSciNotation object at 0x000001E8074AEB88>
<matplotlib.ticker.LogFormatterSciNotation object at 0x000001E8074ADB48>

我们看到主要和次要刻度的位置都是使用​​LogLocator​​​来设置的(对于对数图表来说那是理所当然的)。然而次要刻度的标签的格式是​​NullFormatter​​:这表示次要刻度不会显示标签。

译者注:新版 Matplotlib 已经修改,可以看到 Formatter 都统一成为了 LogFormatterSciNotation,再根据图表实际情况选择是否展示标签。

下面我们就可以开始介绍一些设置这些 locator 和 formatter 的例子了。

隐藏刻度和标签

也许最常见的刻度/标签格式设置的操作是隐藏刻度或标签。这可以通过使用​​plt.NullLocator()​​​和​​plt.NullFormatter()​​来设置,如下例:

ax = plt.axes()
ax.plot(np.random.rand(50))

ax.yaxis.set_major_locator(plt.NullLocator())
ax.xaxis.set_major_formatter(plt.NullFormatter())

Matplotlib基础--自定义刻度_Python_02

 注意上图中我们去除了 x 轴的标签(但是保留了刻度或网格线),y 轴的刻度和标签都被去除了。图表中没有刻度和标签在很多情况下很有用,例如,当你希望展示一个图像的网格。比方说,考虑下面的图表,包含着不同的头像,一个很常见的有监督机器学习问题:

fig, ax = plt.subplots(5, 5, figsize=(5, 5))
fig.subplots_adjust(hspace=0, wspace=0)

# 从scikit-learn载入头像数据集
from sklearn.datasets import fetch_olivetti_faces
faces = fetch_olivetti_faces().images

for i in range(5):
for j in range(5):
ax[i, j].xaxis.set_major_locator(plt.NullLocator())
ax[i, j].yaxis.set_major_locator(plt.NullLocator())
ax[i, j].imshow(faces[10 * i + j], cmap="bone")

downloading Olivetti faces from
​​​https://ndownloader.figshare.com/files/5976027​​to C:\Users\gdc\scikit_learn_data

Matplotlib基础--自定义刻度_自定义_03

注意上图中每张图像都有它自己的 axes,我们将每一个 axes 的 locator 都设置为 null 因为这些刻度值(像素值)在这里并没有任何实际意义。

减少或增加刻度的数量

默认设置的一个常见问题是当子图表较小时,刻度标签可能会粘在一起。我们可以从下面例子看到:

fig, ax = plt.subplots(4, 4, sharex=True, sharey=True)

Matplotlib基础--自定义刻度_自定义_04

特别是 x 轴,标签的数字就快重叠在一起了,这让这些标签难以认清。我们可以通过​​plt.MaxNLocator()​​来修正这点,用它可以设置最大展示刻度的数量。Matplotlib 会自己计算按照这个最大数量计算的刻度位置:

# 对x和y轴设置刻度最大数量
for axi in ax.flat:
axi.xaxis.set_major_locator(plt.MaxNLocator(3))
axi.yaxis.set_major_locator(plt.MaxNLocator(3))
fig

Matplotlib基础--自定义刻度_Python_05

上图就清晰多了。如果你希望对于刻度位置进行更加精细的控制,你可以使用​​plt.MultipleLocator​​,我们会接下来讨论这个对象。

复杂的刻度格式

Matplotlib 的默认刻度格式只能在很多常见情况下工作良好,但是在特殊情况下你会希望能够更多的进行个性化。考虑下面的正弦和余弦图表:

# 绘制正弦和余弦图表
fig, ax = plt.subplots()
x = np.linspace(0, 3 * np.pi, 1000)
ax.plot(x, np.sin(x), lw=3, label='Sine')
ax.plot(x, np.cos(x), lw=3, label='Cosine')

# 设置网格、图例和轴极限
ax.grid(True)
ax.legend(frameon=False)
ax.axis('equal')
ax.set_xlim(0, 3 * np.pi);

Matplotlib基础--自定义刻度_Python_06

 这里有几个我们希望进行的改变。首先,如果刻度的间距和网格线是  的倍数会显得更加自然。我们可以通过​​MultipleLocator​​来设置它,这个对象用来设置刻度的配置。为了更直观,我们设置主要刻度为pai/2  位置,设置次要刻度为pai/4  位置:

Matplotlib基础--自定义刻度_字符串_07

 但是上图看起来有点傻:我们可以看出刻度确实是 pai 的倍数,但是使用了小数的展示让它们看起来很奇怪。要修正这些标签,我们需要修改刻度的 formatter。在这种情况中,没有內建的 formatter 可以给我们使用,因此我们使用​​plt.FuncFormatter​​,这个对象能够接受一个用户自定义的函数来提供对于刻度标签的精细控制:

def format_func(value, tick_number):
# N是pi/2的倍数
N = int(np.round(2 * value / np.pi))
if N == 0:
return "0" # 0点
elif N == 1:
return r"$\frac{\pi}{2}$" # pi/2
elif N == 2:
return r"$\pi$" # pi
elif N % 2 > 0:
return r"$\frac{{%d}\pi}{2}$" %N # n*pi/2 n是奇数
else:
return r"${0}\pi$".format(N // 2) # n*pi n是整数

ax.xaxis.set_major_formatter(plt.FuncFormatter(format_func))
fig

Matplotlib基础--自定义刻度_图例_08

上图看起来好多了。注意到我们使用到了 Matplotlib 的 LaTeX 支持,使用美元符号将 LaTeX 字符串括起来。这是用来展示数学符号和公式的简便方法:在这个例子中​​"$\pi$"​​被渲染成希腊字母 。

​plt.FuncFomatter()​​提供了对于图表刻度最高级的自定义和精细控制,并且当你需要创建需要印刷或出版的图表时非常方便。

Formatter 和 Locator 总结

我们已经介绍了一些 formatter 和 locator。在最后我们通过将內建的 locator 和 formatter 参数列出来对本节做一个总结。要获得更多相关内容,请参阅文档或 Matplotlib 的在线文档。下表中列出的对象在​​plt​​命名空间中都是有效的:

Locator 对象

描述

​NullLocator​

无刻度

​FixedLocator​

固定刻度位置

​IndexLocator​

序号图表刻度 (例如 x = range(len(y)))

​LinearLocator​

从最小到最大值的均匀分割刻度

​LogLocator​

从最小到最大值的对数分割刻度

​MultipleLocator​

某个基数的倍数刻度

​MaxNLocator​

刻度数量最大值

​AutoLocator​

默认的刻度数量最大值

​AutoMinorLocator​

默认的次要刻度

Formatter 对象

描述

​NullFormatter​

无标签

​IndexFormatter​

从一个列表获得标签

​FixedFormatter​

从固定的字符串设置标签

​FuncFormatter​

使用自定义函数设置标签

​FormatStrFormatter​

使用一个格式化字符串设置标签

​ScalarFormatter​

默认的标量标签

​LogFormatter​

默认的对数标签