在实际绘图时,如果 x , y x,y x,y这两轴的数据变化速率相差过多,线性的坐标映射将无法展示图形变化的细节,就需要更改坐标系的数字映射逻辑,以获得更具细节的图像。
在matplotlib绘图时,通过set_xscale和set_yscale这两个函数,可以轻松对坐标系进行坐标放缩,并且提供了4个基础的放缩模板,分别是’linear’, ‘log’, ‘symlog’, ‘logit’。
import numpy as np
import matplotlib.pyplot as plt
xs = np.linspace(-5,5,1000)
labels = ['linear', 'log', 'symlog', 'logit']
fig = plt.figure()
for i,L in enumerate(labels, 1):
ax = fig.add_subplot(2,2,i)
ax.plot(xs, np.tan(xs))
ax.plot(xs, np.exp(xs))
ax.set_yscale(L)
ax.set_title(L)
ax.grid()
plt.tight_layout()
plt.show()
从其y轴坐标可以看出,linear就是最常见的线性映射;log是对数坐标;symlog是“双”对数坐标;logit则是中间大、两端小的对数映射。
所以,在log图中,由于对数映射是非对称的,其y轴坐标从小到大依次是 0.01 , 0.1 , 1 , 10 , 100 0.01,0.1,1,10,100 0.01,0.1,1,10,100,所以 尽管 tan x \tan x tanx本应上下对称,但下方却直接超出了坐标轴给定的范围。
set_xscale和set_yscale这两个函数,除了支持matplotlib实现好的字符串标识之外,还支持自定义函数映射。例如,想把y轴映射为 y \sqrt{y} y,则需要定义两个函数,分别用于坐标系映射和图像映射,具体代码如下
forward = lambda x : x**(1/2)
inverse = lambda x : x**2
fig, ax = plt.subplots()
xs = np.linspace(0,4,100)
ax.plot(xs, np.exp(xs))
ax.set_yscale('function', functions=(forward, inverse))
ax.set_title('function: $x^{1/2}$')
ax.grid()
plt.tight_layout()
plt.show()
绘图结果如下
可以看到,y轴方向等间隔的刻度,其映射的长度是依次减半的。10到20在y向的长度,差不多是0到10的二分之一。
虽然上面的例程均通过plot图来演示,但set_xscale和set_yscale其实适用于各种图像。而针对折线图的对数坐标图,matplotlib已经实现了更加成熟的封装,即semilogx, semilogy和loglog。
fig, (ax1, ax2, ax3) = plt.subplots(1,3, figsize=(8,3))
ax1.semilogx(t, np.sin(2 * np.pi * t))
ax1.set(title='semilogx')
ax1.grid()
ax2.semilogy(t, np.exp(-t / 5.0))
ax2.set(title='semilogy')
ax2.grid()
ax3.loglog(t, 20 * np.exp(-t / 10.0))
ax3.set(title='loglog')
ax3.grid()
plt.tight_layout()
plt.show()
结果为
其中,semilogx和semilogy顾名思义,分别是对x轴和y轴进行坐标映射,而loglog则对两个轴都进行了坐标映射。