编写一个后端 -- pyplot 接口#

本页面假设您已对 后端 页面的信息有基本了解,并且旨在为第三方后端实现者提供参考。本页面仅涉及后端与 pyplot 之间的交互,不涉及渲染方面,渲染方面的内容在 backend_template 中描述。

定义后端的API有两种:一种是基于画布的新API(在Matplotlib 3.6中引入),另一种是较旧的基于函数的API。新API实现起来更简单,因为许多方法可以从“父后端”继承。如果不需要考虑Matplotlib < 3.6的向后兼容性,建议使用新API。然而,旧的API仍然得到支持。

从根本上说,后端模块需要向 pyplot 提供信息,以便

  1. pyplot.figure() 可以创建一个新的 Figure 实例,并将其与一个由后端提供的画布类实例关联,该画布类实例本身托管在一个由后端提供的管理类实例中。

  2. pyplot.show() 可以显示所有图形并启动GUI事件循环(如果有)。

为此,后端模块必须定义一个 backend_module.FigureCanvas 类,它是 FigureCanvasBase 的子类。在基于画布的API中,这是后端模块的唯一严格要求。基于函数的API还需要定义许多模块级函数。

基于画布的 API (Matplotlib >= 3.6)#

  1. 创建图形: pyplot.figure() 调用 figure = Figure(); FigureCanvas.new_manager(figure, num)new_manager 是一个类方法)来实例化一个画布和一个管理器,并设置 figure.canvasfigure.canvas.manager 属性。图形的解封装使用相同的方法,但用解封装的图形替换新实例化的 Figure()

    交互式后端应通过将 FigureCanvas.manager_class 属性设置为所需的 manager 类来自定义 new_manager 的效果,并且(如果画布不能在 manager 之前创建,如 wx 后端的情况)通过重写 FigureManager.create_with_canvas 类方法。(非交互式后端通常可以使用简单的 FigureManagerBase,因此可以跳过此步骤。)

    在通过 pyplot 注册了一个新图形(无论是通过 pyplot.figure() 还是通过解封)后,如果在交互模式下,pyplot 将调用其画布的 draw_idle() 方法,该方法可以根据需要进行重写。

  2. 显示图形: pyplot.show() 调用 FigureCanvas.manager_class.pyplot_show() (一个类方法),传递任何参数,以启动主事件循环。

    默认情况下,pyplot_show() 会检查是否有任何 managers 注册在 pyplot 中(如果没有则提前退出),调用所有此类 manager.show(),然后,如果以 block=True 调用(或者使用默认的 block=None 并且不在 IPython 的 pylab 模式下且不在交互模式下),调用 FigureCanvas.manager_class.start_main_loop()``(一个类方法)来启动主事件循环。因此,交互式后端应相应地重写 ``FigureCanvas.manager_class.start_main_loop 类方法(或者,它们也可以直接重写 FigureCanvas.manager_class.pyplot_show)。

基于函数的API#

  1. 创建图形: pyplot.figure() 调用 new_figure_manager(num, *args, **kwargs) (这也会负责创建新的图形为 Figure(*args, **kwargs));解封装调用 new_figure_manager_given_figure(num, figure)

    此外,在交互模式下,可以通过提供模块级别的 draw_if_interactive() 函数来自定义新注册图形的首次绘制。(在新的基于画布的API中,不再考虑此函数。)

  2. 显示图形pyplot.show() 调用了一个模块级的 show() 函数,该函数通常通过 ShowBase 类及其 mainloop 方法生成。

注册一个后端#

要让一个新的后端能够通过 matplotlib.use() 或 IPython 的 %matplotlib 魔法命令使用,它必须与 BackendRegistry 支持的三种方式之一兼容:

内置#

Matplotlib 内置的后端必须在 BackendRegistry 中硬编码其名称和 FigureCanvas.required_interactive_framework。如果后端模块不是 f"matplotlib.backends.backend_{backend_name.lower()}",那么在 BackendRegistry._name_to_module 中也必须有一个条目。

module:// 语法#

任何在单独模块中的后端(未内置于 Matplotlib)都可以通过指定模块路径的形式来使用,例如 module://some.backend.module。一个例子是 module://mplcairo.qt 用于 mplcairo。后端的交互框架将从其 FigureCanvas.required_interactive_framework 中获取。

入口点#

外部后端模块可以通过在其 pyproject.toml 中使用 entry point 来自我注册为后端,例如 matplotlib-inline 所使用的方式:

[project.entry-points."matplotlib.backend"]
inline = "matplotlib_inline.backend_inline"

后端的交互框架将从其 FigureCanvas.required_interactive_framework 中获取。所有入口点一起加载,但仅在首次需要时加载,例如当后端名称未被识别为内置后端时,或当 list_all() 首次被调用时。