python matplotlib笔记:交互方式

python matplotlib笔记1:交互方式

1、matplotlib交互方式

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

Matplotlib有两种主要的应用接口或使用库的方式:

一种是显式的“Axes”接口(explicit),它使用Figure或Axes对象上的方法创建图像效果,并逐步构建可视化。这也被称为“面向对象”的接口。

另一种是隐式的“pyplot”接口(implicit),它跟踪最后创建的Figure和Axes,并将图像效果添加到它认为用户想要的对象中。

此外,许多下游库(如pandas和xarray)在其数据类上直接实现了plot方法,以便用户可以调用data.plot()。

这些接口之间的差异可能有点令人困惑,特别是在网络上使用其中一种或多种接口的代码片段。在这里,我们试图指出“pyplot”和下游接口与显式“Axes”接口之间的关系,以帮助用户更好地使用该库。

2、两种交互方式的区别

显式的交互方式:

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

python matplotlib笔记:交互方式_第1张图片

因为每个对象都明确引用并用于创建下一个对象。保留对这些对象的引用非常灵活,并允许我们在创建它们后但在显示之前自定义这些对象。

隐式的交互方式

pyplot模块对大多数Axes绘图方法进行了封装,以提供与上述相同的功能,其中Figure和Axes的创建已经由库完成,无需用户进行操作:

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

python matplotlib笔记:交互方式_第2张图片

这很方便,特别是在进行交互式工作或编写简单脚本时。可以使用gcf获取对当前Figure的引用,使用gca获取对当前Axes的引用。pyplot模块会保留Figure的列表,并且每个Figure为用户保留在图上的Axes列表,因此可以通过以下方式实现:

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])

python matplotlib笔记:交互方式_第3张图片

等价于显式方式:

import matplotlib.pyplot as plt

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

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

3、两种交互的应用场景

如果你需要回溯,并操作一个不被plt.gca()引用的旧Axes,会发生什么?一种简单的方法是使用相同的参数再次调用subplot。然而,这很快就变得不雅观了。您还可以检查Figure对象并获取其Axes对象列表,但是这可能会引起误解(颜色设置也属于Axes!)。

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')

python matplotlib笔记:交互方式_第4张图片

最好的解决方案可能是保存每个创建的Axes的句柄,但如果这样做,为什么不在开始时创建所有Axes对象呢?

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')

推荐的方法:

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')

数据对象的交互方式

一些第三方库选择为其数据对象实现绘图,例如,在pandas、xarray和其他第三方库中可以看到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()

因此,该库可以将所有复杂的细节隐藏起来,可以根据数据类型创建适当的可视化,通常具有良好的标签、色图选择和其他方便的功能。

然而,在上述示例中,我们可能不喜欢库提供的标题。幸运的是,他们从plot()方法中将Axes传回给我们,因此我们可以使用显式的Axes接口调用ax.set_title(‘My preferred title’)来自定义标题。

许多库还允许其plot方法接受一个可选的ax参数。这使我们可以将可视化放置在我们已经放置并可能定制的Axes中。

总结:
总的来说,理解显式“Axes”接口非常有用,因为它是最灵活的接口,并支持其他接口。用户通常可以找出如何进入显式接口并操作底层对象。虽然显式接口可能需要更多的设置步骤,但是相比尝试使用隐式的“pyplot”接口,复杂的绘图通常会变得更简单。


你可能感兴趣的:(python,matplotlib,pandas)