MEP27:从后端分离Pyplot¶
分支和请求¶
主PR(包括GTK3):+https://github.com/matplotlib/matplotlib/pull/4143
后端特定分支差异:+https://github.com/oceanwolf/matplotlib/compare/backend refactor…oceanwolf:后端重构tkagg+https://github.com/oceanwolf/matplotlib/compare/backend refactor…oceanwolf:后端重构qt+https://github.com/oceanwolf/matplotlib/compare/backend refactor…后端重构wx
摘要¶
此MEP重构后端以提供更结构化和一致的API,删除通用代码并合并现有代码。为此,我们建议拆分:
FigureManagerBase
及其派生类到核心功能类FigureManager
以及后端特定类WindowBase
和ShowBase
它的派生类Gcf.show_all
和MainLoopBase
.
详细描述¶
此MEP旨在将后端API合并为一个统一的API,从后端删除通用代码(包括 _pylab_helpers
和 Gcf
)并将代码推送到Matplotlib中更合适的级别。这样,我们可以自动删除后端出现的不一致,例如 FigureManagerBase.resize(w, h)
它有时设置画布,有时根据后端设置整个窗口的尺寸。
泛型代码的两个主要位置出现在派生自 FigureManagerBase
和 ShowBase
.
FigureManagerBase
有 三 目前的工作:- 文档将其描述为 ``Helper class for pyplot mode, wraps everything up into a neat bundle''
- 但它不仅包装了画布和工具栏,还完成了所有窗口化任务本身。这两个任务的合并在下面一行中表现得最好:
`python self.set_window_title("Figure %d" % num) `` `这结合了后端特定的代码 ``self.set_window_title(title)
使用Matplotlib通用代码title = "Figure %d" % num
. - 当前的后端特定子类
FigureManager
决定何时结束主循环。这似乎也是非常错误的,因为数字不应该控制其他数字。
ShowBase
有两个工作:- 它的任务是检查所有在
_pylab_helpers.Gcf
告诉他们要表现自己。 - 其次,它有执行后端特定的任务
mainloop
阻止主要节目,从而防止数字死亡。
- 它的任务是检查所有在
实施¶
此MEP的描述为我们提供了大部分解决方案:
- 从中移除窗口
FigureManagerBase
让它简单地将这个新类和其他后端类包装在一起。创建新的WindowBase
使用传递方法(:arrow_right:)可处理此功能的类WindowBase
. 子类的类WindowBase
还应该对特定于GUI的窗口类进行子类化,以确保向后兼容性 (manager.window == manager.window
) - 重构的主循环
ShowBase
进入之内MainLoopBase
它也封装了循环的结尾。我们举一个例子MainLoop
到FigureManager
作为一个键,解锁exit方法(要求在循环结束之前返回所有键)。注意,这为多个后端同时运行打开了可能性。 - 既然
FigureManagerBase
其中没有后端细节,将其重命名为FigureManager
,并移动到新文件backend_managers.py
注意:- 这允许我们将后端转换为单独的prs,因为我们可以保留现有的
FigureManagerBase
类及其依赖项完好无损。 - 这也预示着MEP22在
NavigationBase
已变形为后端独立ToolManager
.
- 这允许我们将后端转换为单独的prs,因为我们可以保留现有的
FigureManagerBase(画布,数字) | FigureManager(数字,数字) | WindowBase(title) |
笔记 |
---|---|---|---|
显示 | 显示 | ||
破坏 | 调用销毁所有组件 | 破坏 | |
full_screen_toggle | 句柄逻辑 | set_fullscreen | |
调整大小 | 调整大小 | ||
key_press | key_press | ||
get_window_title | get_window_title | ||
set_window_title | set_window_title | ||
_get_toolbar | FigureManagerBase所有子类的通用方法 | ||
set_default_size | |||
add_element_to_window |
ShowBase | MainLoopBase | 笔记 |
---|---|---|
主回路 | 开始 | |
结束 | 当子类的实例不存在时自动调用 | |
__call__ | 方法移到gcf.showu all |
未来的兼容性¶
正如上面讨论MEP22时所回避的,这个重构使得添加新的通用特性变得容易。目前,MEP22必须对每个类进行丑陋的黑客攻击,从 FigureManagerBase
. 使用此代码,只需在单个 FigureManager
班级。这也使得后来的 NavigationToolbar2
非常简单,只需要触摸单曲 FigureManager
班
MEP23提供了另一个用例,在这个用例中,重构的代码将非常方便。
向后兼容性¶
由于我们保留了所有后端代码的完整性,只向现有类添加了缺失的方法,因此对于所有用例来说,这应该是无缝的。唯一的区别在于使用的后端 FigureManager.resize
根据API的标准化,调整画布而不是窗口的大小。
我可以预见,这个重构所废弃的类将被弃用,并按照与之相同的时间表删除。 NavigationToolbar2
同时请注意,呼叫签名的更改 FigureCanvasWx
构造函数,虽然向后兼容,但我认为旧的(imho丑陋样式)签名应该被弃用,并以与其他所有签名相同的方式删除。
后端 | 管理器。调整大小(w,h) | 额外的 |
---|---|---|
GTK3 | 窗口 | |
TK | 帆布 | |
QT | 窗口 | |
WX | 帆布 | FigureManagerWX曾经 frame 作为窗口的别名,所以这也会破坏BC。 |
问题¶
MDehoon:您能详细说明如何同时运行多个后端吗?
大洋狼:@mdehoon,正如我所说,不是为这个MEP,但我看到这个MEP打开了未来的可能性。基本上 MainLoopBase
类对每个后端GCF起作用,在该MEP中,它跟踪每个后端打开的图的数量,并管理这些后端的主循环。当检测到该后端没有打开的数据时,它将关闭后端特定的主循环。正因为如此,我认为只要稍作调整,我们就可以完成完整的多后端Matplotlib。还不知道为什么会有人想要,但我把可能性留在了mainloopbase。所有后端代码细节都重构出来 FigureManager
同时也有助于这一点,一个经理来管理他们(后端)的所有。
梅洪:@oceanwolf,好的,谢谢你的解释。后端有一个统一的API对于Matplotlib的可维护性非常重要。我认为这个MEP朝着正确的方向迈出了一步。