编写后端 -- pyplot 接口#
本页假设读者已对 后端 (Backends) 页面中的信息有了大致了解,旨在为第三方后端实现者提供参考。它仅涉及后端与 pyplot 之间的交互,而不涉及渲染方面的内容,后者在 backend_template 中有详细描述。
定义后端有两种 API:一种是基于画布(canvas)的新 API(引入于 Matplotlib 3.6),另一种是较旧的基于函数(function)的 API。新 API 实现起来更简单,因为许多方法可以从“父后端”继承。如果不考虑 Matplotlib < 3.6 的向后兼容性,推荐使用新 API。不过,旧 API 仍然得到支持。
从根本上讲,后端模块需要向 pyplot 提供信息,以便
pyplot.figure()能够创建一个新的Figure实例,并将其与后端提供的画布类实例相关联,该画布本身由后端提供的管理器类实例托管。pyplot.show()能够显示所有图形并启动 GUI 事件循环(如果有的话)。
为此,后端模块必须定义一个 FigureCanvasBase 的子类 backend_module.FigureCanvas。在基于画布的 API 中,这是后端模块唯一严格的要求。而基于函数的 API 还要求定义许多模块级函数。
基于画布的 API (Matplotlib >= 3.6)#
创建图形:
pyplot.figure()调用figure = Figure(); FigureCanvas.new_manager(figure, num)(new_manager是一个类方法)来实例化一个画布和一个管理器,并设置figure.canvas和figure.canvas.manager属性。图形反序列化(unpickling)使用相同的方法,但会用反序列化后的图形替换新实例化的Figure()。交互式后端应通过将
FigureCanvas.manager_class属性设置为所需的管理器类来自定义new_manager的效果;如果无法在管理器之前创建画布(如 wx 后端的情况),则还需重写FigureManager.create_with_canvas类方法。(非交互式后端通常可以使用简单的FigureManagerBase,因此可以跳过此步骤。)当一个新的图形通过
pyplot注册(通过pyplot.figure()或反序列化)后,如果处于交互模式,pyplot将调用其画布的draw_idle()方法,该方法可以根据需要进行重写。显示图形:
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#
创建图形:
pyplot.figure()调用new_figure_manager(num, *args, **kwargs)(该函数同时也负责通过Figure(*args, **kwargs)创建新图形);反序列化则调用new_figure_manager_given_figure(num, figure)。此外,在交互模式下,可以通过提供模块级的
draw_if_interactive()函数来自定义新注册图形的首次绘制。(在新的基于画布的 API 中,该函数不再被考虑。)显示图形:
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。例如 mplcairo 使用的 module://mplcairo.qt。后端的交互式框架将从其 FigureCanvas.required_interactive_framework 获取。
入口点 (Entry point)#
外部后端模块可以使用其 pyproject.toml 中的 entry point 自行注册为后端,例如 matplotlib-inline 所使用的方式。
[project.entry-points."matplotlib.backend"]
inline = "matplotlib_inline.backend_inline"
后端的交互式框架将从其 FigureCanvas.required_interactive_framework 获取。所有入口点会一起加载,但仅在首次需要时才加载,例如当某个后端名称未被识别为内置后端,或者首次调用 list_all() 时。