融会贯通matplotlib接口——显式与隐式的区别(explicit vs implicit),不再迷茫

matplotlib接口——显示与隐式的区别(explicit vs implicit)

我很肯定,不少人在学习或使用matplotlib绘图时,总是看到不同的调用方法,如果恰恰与自己的使用习惯相反的话,也会一时不知所措。

希望看完本片内容后,你会有所收获,对不同的编码方式都能融会贯通

Matplotlib有两大接口,也是两种不同的使用风格

  • 轴区(Axes)接口,也就是显式接口,直接在图形(Figure)或轴区(Axes)对象上调用方法来创建艺术器(Artist),一步步地完成可视化过程。这又叫做“面向对象”接口(object-oriented interface)。
  • pyplot接口,即隐式接口,会始终追踪到最新创建的图形(Figure)和轴区(Axes),通过猜测用户的想法而将艺术器(Artist)添加到目标对象上。

另外,pandas和xarray等库可以使用内置的plot函数来绘图,使用方法:data.plot()。
这些接口的差别很微妙,特别是网络上的一些代码片段,或者是在某些例子中混合使用多个接口

原生的Matplotlib接口

Axes显式接口

Axes接口是Matplotlib的实现方式。在此基础上用户可以完成多项自定义配置和微调。

本接口会实例化Figure类为一个对象(fig),调用subplots函数在该对象上创建一个或多个axes(轴区,ax),最后在axes上调用绘图函数(plot)。

import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.subplots()
ax.plot([1, 2, 3, 4], [0, 0.5, 1, 0.2])

plt.show()

将其称为显式接口就是因为每个对象都是直接调用的,并用于创建下一个对象。保持对对象的调用是非常灵活的,我们可以在对象创建后、绘制前对其随意配置。

pyplot隐式接口

pyplot模块隐藏了Axes大部分的绘图函数,替代用户完成例如上面展示的Figure和Axes创建的操作。

import matplotlib.pyplot as plt

plt.plot([1, 2, 3, 4], [0, 0.5, 1, 0.2])

plt.show()

本接口在执行交互工作或简单的脚本时很方便。使用gcf和gca可以分别调用当前Figure和Axes。pyplot会储存一个由Figures组成的列表,每个Figures又储存了该图形上所有Axes组成的列表。

import matplotlib.pyplot as plt

plt.subplot(1, 2, 1) # 前面的1,2表示创建1行有2个axes的figure,最后的1表示调用第1个axes,隐藏了调用axes
plt.plot([1, 2, 3], [0, 0.5, 0.2])

plt.subplot(1, 2, 2) # 前面的1,2表示创建1行有2个axes的figure,最后的1表示调用第2个axes,隐藏了调用axes
plt.plot([3, 2, 1], [0, 0.5, 0.2])

plt.show()

下面的代码与上方实现同样的效果:

import matplotlib.pyplot as plt

plt.subplot(1, 2, 1) # 前面的1,2表示创建1行有2个axes的figure,最后的1表示调用第1个axes
ax = plt.gca() # 通过gca()调用当前的axes,即第1个
ax.plot([1, 2, 3], [0, 0.5, 0.2])

plt.subplot(1, 2, 2) # 前面的1,2表示创建1行有2个axes的figure,最后的1表示调用第2个axes
ax = plt.gca() # 通过gca()调用当前的axes,即第2个
ax.plot([3, 2, 1], [0, 0.5, 0.2])

plt.show()

显式接口是这么实现的:

import matplotlib.pyplot as plt

fig, axs = plt.subplots(1, 2)
axs[0].plot([1, 2, 3], [0, 0.5, 0.2])
axs[1].plot([3, 2, 1], [0, 0.5, 0.2])

plt.show()

为什么要有显式接口

当你不得不回溯到先前的Axes进行操作却不能通过plt.gca()调用时,你会怎么做呢?一个简单的办法就是用相同的参数再次调用subplot()函数。这样显得太野蛮了,你也可以通过Figures的Axes列表来定位,但很可能会出错,因为colorbar也是一种轴区(Axes)。最理想的是你给创建的每个Axes保存具柄,但何不一开始就创建好所有的Axes,又何必再回头呢?

下面用代码展示下前文提到的使用plt.pyplot函数再次调用:

import matplotlib.pyplot as plt

plt.subplot(1, 2, 1)
plt.plot([1, 2, 3], [0, 0.5, 0.2])

plt.subplot(1, 2, 2)
plt.plot([3, 2, 1], [0, 0.5, 0.2])

plt.suptitle('Implicit Interface: re-call subplot')

for i in range(1, 3):
    plt.subplot(1, 2, i)
    plt.xlabel('Boo')

plt.show()

再看看添加句柄的代码实现:

import matplotlib.pyplot as plt

axs = []
ax = plt.subplot(1, 2, 1)
axs += [ax]
plt.plot([1, 2, 3], [0, 0.5, 0.2])

ax = plt.subplot(1, 2, 2)
axs += [ax]
plt.plot([3, 2, 1], [0, 0.5, 0.2])

plt.suptitle('Implicit Interface: save handles')

for i in range(2):
    plt.sca(axs[i])
    plt.xlabel('Boo')

plt.show()

最后,在起始阶段就调用显式接口

import matplotlib.pyplot as plt

fig, axs = plt.subplots(1, 2)
axs[0].plot([1, 2, 3], [0, 0.5, 0.2])
axs[1].plot([3, 2, 1], [0, 0.5, 0.2])
fig.suptitle('Explicit Interface')
for i in range(2):
    axs[i].set_xlabel('Boo')

plt.show()

第三方库的“Data对象”接口

一些第三方库可以用它们的data对象绘图,比如pandas的data.plot()。

为了便于演示,这样的数据可能仅仅储存了x和y数据,然后调用plot函数

import matplotlib.pyplot as plt

# supplied by downstream library:
class DataContainer:

    def __init__(self, x, y):
        """
        Proper docstring here!
        """
        self._x = x
        self._y = y

    def plot(self, ax=None, **kwargs):
        if ax is None:
            ax = plt.gca()
        ax.plot(self._x, self._y, **kwargs)
        ax.set_title('Plotted from DataClass!')
        return ax


# what the user usually calls:
data = DataContainer([0, 1, 2, 3], [0, 0.2, 0.5, 0.3])
data.plot()

可以看到,第三方库把累活都干了,然后让Data类型有了绘图(plot)功能。
许多第三方库的plot函数都接受ax参数。这就让用户有了更多调整的机会。

总结

平心而论,理解Axes显式接口受益无穷,它不但使用起来很灵活,还是其他接口的底层。我们应该学会使用显式接口并对底层对象进行操作。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ALittleHigh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值