MEP27:将 pyplot 与后端解耦#

状态#

进步

分支和拉取请求#

主要公关(包括 GTK3):

后端特定的分支差异:

摘要#

此 MEP 重构后端以提供更结构化和一致的 API,删除通用代码并整合现有代码。为此,我们建议拆分:

  1. FigureManagerBase及其派生类分为核心功能类FigureManager和后端特定类 WindowBase

  2. ShowBase及其派生类到Gcf.show_allMainLoopBase

详细说明#

该 MEP 旨在将后端 API 整合到一个统一的 API 中,从后端(包括 _pylab_helpersGcf)中删除通用代码,并将代码推送到 matplotlib 中更合适的级别。有了这个,我们会自动删除后端中出现的不一致,例如 有时设置画布,有时将整个窗口设置为给定的尺寸,具体取决于后端。FigureManagerBase.resize(w, h)

泛型代码的两个主要位置出现在派生自 FigureManagerBase和的类中ShowBase

  1. FigureManagerBase目前有三份工作:

    1. 文档将其描述为 pyplot 模式的 Helper 类,将所有内容打包成一个整洁的包

    2. 但它不只是包装画布和工具栏,它本身还执行所有窗口任务。这两个任务的结合在以下行中得到了最好的体现: 这结合了后端特定代码和 matplotlib 通用代码。self.set_window_title("Figure %d" % num)self.set_window_title(title)title = "Figure %d" % num

    3. 目前后端特定子类FigureManager 决定何时结束主循环。这似乎也很错误,因为该数字不应控制其他数字。

  2. ShowBase有两个工作:

    1. 它的工作是遍历所有注册的人物经理_pylab_helpers.Gcf并告诉他们展示自己。

    2. 其次,它负责执行特定的后端 mainloop以阻止主程序,从而防止数字死亡。

实施#

该 MEP 的描述为我们提供了大部分解决方案:

  1. 删除窗口方面,FigureManagerBase让它简单地将这个新类与其他后端类一起包装。创建一个WindowBase可以处理此功能的新类,使用传递方法 (:arrow_right:) 到 WindowBase. 子类的类WindowBase也应该是 GUI 特定窗口类的子类,以确保向后兼容 ( )。manager.window == manager.window

  2. 重构 into 的ShowBaseMainLoopBase循环,它也封装了循环的结尾。我们给出一个 MainLoopto的实例FigureManager作为解锁退出方法的键(要求在循环终止之前返回所有键)。请注意,这为多个后端同时运行提供了可能性。

  3. 现在它FigureManagerBase没有后端细节,将其重命名为FigureManager,并移动到一个新文件 backend_managers.py,注意:

    1. 这使我们能够将后端转换为单独的 PR,因为我们可以保持现有FigureManagerBase 类及其依赖项完好无损。

    2. 这也预示了 MEP22 中新的 NavigationBase已经演变成后端独立的 ToolManager.

FigureManagerBase(canvas, num)

图管理器(图,数字)

WindowBase(title)

笔记

节目

节目

破坏

对所有组件调用destroy

破坏

全屏切换

处理逻辑

设置全屏

调整大小

调整大小

按键

按键

获取窗口标题

获取窗口标题

设置窗口标题

设置窗口标题

_get_toolbar

FigureManagerBase 所有子类的通用方法

设置默认大小

add_element_to_window

展示基地

主循环库

笔记

主循环

开始

结尾

当不存在子类的更多实例时自动调用

__称呼__

方法移至 Gcf.show_all

未来的兼容性#

正如上面讨论 MEP 22 时所回避的那样,这种重构使得添加新的通用特性变得容易。目前,MEP 22 必须对从FigureManagerBase. 使用此代码,只需在单个FigureManager 类中进行。这也使得后面的 deprecation NavigationToolbar2非常直接,只需要碰单FigureManager

MEP 23 提供了另一个用例,这个重构的代码将非常方便。

向后兼容性#

由于我们保持所有后端代码不变,只向现有类添加缺少的方法,这应该适用于所有用例。由于 API 的标准化,唯一的区别在于用于 FigureManager.resize调整画布而不是窗口大小的后端。

我会设想这个重构过时的类在与 相同的时间表上被弃用和删除 NavigationToolbar2,还请注意对FigureCanvasWx构造函数的调用签名的更改,虽然向后兼容,但我认为旧的(恕我直言丑陋的风格)签名应该被弃用并以与其他所有内容相同的方式删除。

后端

manager.resize(w,h)

额外的

gtk3

窗户

总热量

帆布

Qt

窗户

Wx

帆布

FigureManagerWx frame作为 window 的别名,所以这也破坏了 BC。

替代方案#

如果有任何替代解决方案来解决相同的问题,则应在此处对其进行讨论,并说明所选方法的理由。

问题#

Mdehoon:您能否详细说明如何同时运行多个后端?

OceanWolf:@mdehoon,正如我所说,不是为了这个 MEP,但我认为这个 MEP 开启了它作为未来的可能性。基本上,MainLoopBase 该类充当每个后端 Gcf,在此 MEP 中,它跟踪每个后端打开的图形数量,并管理这些后端的主循环。当它检测到后端没有任何数字保持打开时,它会关闭后端特定的主循环。正因为如此,我想只需要进行少量调整,我们就可以完成完整的多后端 matplotlib。还不知道为什么要这样做,但我将可能性留在了 MainLoopBase 中。由于所有后端代码细节都被重构出来,FigureManager这也有助于这一点,一位经理来统治它们(后端)。

Mdehoon:@OceanWolf,好的,谢谢你的解释。为后端提供统一的 API 对于 matplotlib 的可维护性非常重要。我认为这个 MEP 是朝着正确方向迈出的一步。