mpl-gui 文档#

动机#

本项目是一个原型空间,旨在彻底改革 Matplotlib 在 pyplot 中提供的 GUI 事件循环管理工具。

pyplot 模块目前承担着两个关键但并不相关的功能:

  1. 提供一个受 MATLAB 启发/风格相似的有状态隐式 API

  2. 提供 Matplotlib 与 GUI 事件循环之间交互的管理,包括保持图形(Figures)处于活动状态

虽然在命令行下工作时非常方便,但有状态的 API 可能会导致代码变得脆弱,其运行依赖于以令人困惑的方式存在的全局状态,特别是在库代码中使用时更是如此。另一方面,matplotlib.pyplot 在向用户隐藏“他们正在开发 GUI 应用程序”这一事实方面做得非常好,并且与 IPython 一起处理了许多在 Python 中并行运行 GUI 应用程序所涉及的细节。

示例#

如果你想确保代码不会隐秘地依赖 pyplot,请运行

import sys
sys.modules['matplotlib.pyplot'] = None

这将阻止 pyplot 被导入!

展示(showing)#

API 的核心是 show

import mpl_gui as mg
from matplotlib.figure import Figure

fig1 = Figure(label='A Label!')

fig2 = Figure()

mg.show([fig1, fig2])

它将显示所有图形并阻塞程序运行,直到它们被关闭。作为“展示”过程的一部分,正确的 GUI 对象将被创建并放置在屏幕上,同时运行宿主 GUI 框架的事件循环。

阻塞(或不阻塞)#

类似于 plt.ion 和 plt.ioff,我们提供了具有相同语义的 mg.ion() 和 mg.ioff()。因此

import mpl_gui as mg
from matplotlib.figure import Figure

mg.ion()
print(mg.is_interactive())
fig = Figure()

mg.show([fig])  # will not block

mg.ioff()
print(mg.is_interactive())
mg.show([fig])  # will block!

与 plt.show 一样,你可以通过 block 关键字参数显式控制 mg.show 的阻塞行为

import mpl_gui as mg
from matplotlib.figure import Figure

fig = Figure(label='control blocking')

mg.show([fig], block=False)  # will never block
mg.show([fig], block=True)   # will always block

交互状态是 Matplotlib 共享的,也可以通过 matplotlib.interactive 进行控制,并通过 matplotlib.is_interactive 进行查询。

图形(Figure)与坐标轴(Axes)创建#

仿照 matplotlib.pyplot,我们也提供了 figure、subplots 和 subplot_mosaic

import mpl_gui as mg
fig1 = mg.figure()
fig2, axs = mg.subplots(2, 2)
fig3, axd = mg.subplot_mosaic('AA\nBC')

mg.show([fig1, fig2, fig3])

如果 mpl_gui 处于“交互模式”,mpl_gui.figure、mpl_gui.subplots 和 mpl_gui.subplot_mosaic 将自动把新图形放入屏幕上的窗口中(但不会运行事件循环)。

FigureRegistry#

在上述示例中,用户有责任跟踪所创建的 Figure 实例。如果用户没有直接或间接地通过其子对象保留对 fig 对象的强引用,那么它将像其他 Python 对象一样被垃圾回收。虽然这在某些情况下(例如创建许多临时图形的脚本或函数)是有利的,但它失去了 matplotlib.pyplot 为你跟踪实例的便利性。为此,我们也提供了 FigureRegistry

import mpl_gui as mg

fr = mg.FigureRegistry()

fr.figure()
fr.subplots(2, 2)
fr.subplot_mosaic('AA\nBC')

fr.show_all()     # will show all three figures
fr.show()         # alias for pyplot compatibility

fr.close_all()    # will close all three figures
fr.close('all')   # alias for pyplot compatibility

因此,如果你仅使用 pyplot API 的这一受限集合,那么你可以将

import matplotlib.pyplot as plt

更改为

import mpl_gui as mg
plt = mg.FigureRegistry()

进行更改,并获得一个(几乎是)直接替换的方案。

此外,还有一个 FigureRegistry.by_label 辅助工具,它返回一个将图形标签映射到每个图形的字典

import mpl_gui as mg

fr = mg.FigureRegistry()

figA = fr.figure(label='A')
figB = fr.subplots(2, 2, label='B')

fr.by_label['A'] is figA
fr.by_label['B'] is figB

FigureContext#

一个非常常见的用例是制作多个图形,然后在最后将它们全部显示出来。为了促进这一点,我们提供了一个 FigureRegistry 的子类,可以用作上下文管理器,(在局部)跟踪已创建的图形并在退出时显示它们。

import mpl_gui as mg

with mg.FigureContext() as fc:
    fc.subplot_mosaic('AA\nBC')
    fc.figure()
    fc.subplots(2, 2)

这将创建 3 个图形并在 __exit__ 时阻塞。阻塞行为取决于 mg.is_interacitve()(并遵循 mg.show 的行为,或者可以通过 block 关键字参数显式控制)。

选择 GUI 工具包#

mpl_gui 利用 Matplotlib 后端来实际提供 GUI 绑定。类似于 matplotlib.use 和 matplotlib.pyplot.switch_backend,mpl_gui 提供了 mpl_gui.select_gui_toolkit 来选择使用的 GUI 工具包。select_gui_toolkit 具有与 pyplot 相同的回退行为,并将其状态存储在 rcParams["backend"] 中。mpl_gui 将在同一进程中与 matplotlib.pyplot 管理的图形稳定共存。