MEP27:从后端分离Pyplot

状态

Progress

分支和请求

主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,删除通用代码并合并现有代码。为此,我们建议拆分:

  1. FigureManagerBase 及其派生类到核心功能类 FigureManager 以及后端特定类 WindowBase
  2. ShowBase 它的派生类 Gcf.show_allMainLoopBase .

详细描述

此MEP旨在将后端API合并为一个统一的API,从后端删除通用代码(包括 _pylab_helpersGcf )并将代码推送到Matplotlib中更合适的级别。这样,我们可以自动删除后端出现的不一致,例如 FigureManagerBase.resize(w, h) 它有时设置画布,有时根据后端设置整个窗口的尺寸。

泛型代码的两个主要位置出现在派生自 FigureManagerBaseShowBase .

  1. FigureManagerBase 目前的工作:

    1. 文档将其描述为 ``Helper class for pyplot mode, wraps everything up into a neat bundle''
    2. 但它不仅包装了画布和工具栏,还完成了所有窗口化任务本身。这两个任务的合并在下面一行中表现得最好: `python self.set_window_title("Figure %d" % num) `` `这结合了后端特定的代码 ``self.set_window_title(title) 使用Matplotlib通用代码 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. 重构的主循环 ShowBase 进入之内 MainLoopBase 它也封装了循环的结尾。我们举一个例子 MainLoopFigureManager 作为一个键,解锁exit方法(要求在循环结束之前返回所有键)。注意,这为多个后端同时运行打开了可能性。
  3. 既然 FigureManagerBase 其中没有后端细节,将其重命名为 FigureManager ,并移动到新文件 backend_managers.py 注意:
    1. 这允许我们将后端转换为单独的prs,因为我们可以保留现有的 FigureManagerBase 类及其依赖项完好无损。
    2. 这也预示着MEP22在 NavigationBase 已变形为后端独立 ToolManager .
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朝着正确的方向迈出了一步。