MEP9:全球交互管理器#

为所有用户与艺术家的交互添加一个全局管理器;使任何艺术家可根据用户的需要调整大小、可移动、可突出显示和可选择。

状态#

讨论

分支和拉取请求#

https://github.com/dhyams/matplotlib/tree/MEP9

摘要#

目标是能够以与绘图程序非常相似的方式与 matplotlib 艺术家进行交互。在适当的时候,用户应该能够移动、调整大小或选择已经在画布上的艺术家。当然,剧本作者最终控制着艺术家是否能够与之互动,或者它是否是静态的。

执行此操作的代码已经私下实现和测试,并且需要从其当前的“mixin”实现迁移到 matplotlib 的真正部分。

最终结果是 matplotlib.artist.Artist 可以使用四个新关键字:_moveable_、_resizeable_、_selectable_ 和 _highlightable_。将这些关键字中的任何一个设置为 True 都会激活该艺术家的交互性。

实际上,这个 MEP 是 matplotlib 中事件处理的逻辑扩展;matplotlib 已经支持“低级”交互,例如鼠标左键、按键等。MEP 将支持扩展到逻辑级别,当检测到来自用户的某些交互手势时,将对艺术家执行回调。

详细说明#

这个新功能将用于允许最终用户更好地与图形交互。很多时候,图表几乎是用户想要的,但需要对组件进行小的重新定位和/或调整大小。而不是强迫用户返回脚本来试错位置,简单的拖放是合适的。

此外,这将更好地支持使用 matplotlib 的应用程序;在这里,最终用户没有合理的访问权限或希望编辑底层源以微调绘图。在这里,如果 matplotlib 提供了这种能力,人们可以在画布上移动或调整艺术家的大小以满足他们的需要。此外,如果应用程序支持这种事情,用户应该能够突出显示(用鼠标悬停)艺术家,并通过双击选择它。在这个 MEP 中,我们还希望原生支持高亮和选择;由应用程序来处理选择艺术家时发生的事情。一个典型的处理是显示一个对话框来编辑艺术家的属性。

将来,同样(这不是本 MEP 的一部分),matplotlib 可以为每个艺术家提供特定于后端的属性对话框,这些对话框是在艺术家选择时提出的。该 MEP 将是这种能力的必要垫脚石。

matplotlib 中目前有一些交互功能(例如 legend.draggable()),但它们往往是分散的,并非对所有艺术家都可用。该 MEP 旨在统一交互界面并使其适用于所有艺术家。

当前的 MEP 还包括用于调整艺术家大小的把手,以及在艺术家移动或调整大小时绘制的适当框。

实施#

  • 将适当的方法添加到艺术家的“树”中,以便交互管理器有一个一致的接口供交互管理器处理。如果要支持交互性,建议添加到艺术家的方法是:

    • get_pixel_position_ll(self): 获取艺术家边界框左下角的像素位置

    • get_pixel_size(self):获取艺术家边界框的大小,以像素为单位

    • set_pixel_position_and_size(self,x,y,dx,dy):设置艺术家的新尺寸,使其适合指定的边界框。

  • 将功能添加到后端以 1) 提供光标,因为这些是移动/调整大小的视觉指示所必需的,以及 2) 提供获取当前鼠标位置的函数

  • 实施经理。这已经私下(由 dhyams)作为 mixin 完成,并且已经过相当多的测试。目标是将管理器的功能转移到艺术家中,以便它正确地在 matplotlib 中,而不是像我目前编码的那样作为“猴子补丁”。

当前的 mixin 总结#

(请注意,这个 mixin 目前只是私有代码,但显然可以添加到分支中)

InteractiveArtistMixin:

Mixin 类使在 matplotlib 画布上绘制的任何通用对象可移动并且可能可调整大小。尽可能地遵循 Powerpoint 模型;不是因为我迷恋 Powerpoint,而是因为这是大多数人所理解的。艺术家也可以是可选的,这意味着艺术家将在双击时收到 on_activated() 回调。最后,艺术家可以是可高亮的,这意味着只要鼠标经过,就会在艺术家身上绘制高光。通常,可突出显示的艺术家也将是可选的,但这取决于用户。因此,基本上用户可以为每个艺术家设置四个属性:

  • 突出显示

  • 可选择的

  • 活动

  • 可调整大小

为了可移动(可拖动)或可调整大小,作为 mixin 目标的对象必须支持以下协议:

  • get_pixel_position_ll(自我)

  • 获取像素大小(自我)

  • set_pixel_position_and_size(self,x,y,sx,sy)

请注意,不可调整大小的对象可以随意忽略 sx 和 sy 参数。要突出显示,作为 mixin 目标的对象还必须支持以下协议:

  • get_highlight(自我)

它返回将用于绘制亮点的艺术家列表。

如果 mixin 的目标对象不是 matplotlib 艺术家,则还必须实现以下协议。这样做通常是相当微不足道的,因为在某个地方必须有一位正在绘制的艺术家。通常,您的对象只会将这些调用路由到该艺术家。

  • get_figure(自我)

  • 获取轴(自我)

  • 包含(自我,事件)

  • set_animated(自我,标志)

  • 绘制(自我,渲染器)

  • get_visible(自我)

在艺术家上调用以下通知,艺术家可以选择实现这些。

  • on_select_begin(self)

  • on_select_end(自我)

  • on_drag_begin(self)

  • on_drag_end(self)

  • on_activated(自我)

  • on_highlight(自我)

  • on_right_click(自我,事件)

  • on_left_click(自我,事件)

  • on_middle_click(自我,事件)

  • on_context_click(自我,事件)

  • on_key_up(自我,事件)

  • on_key_down(自我,事件)

如果没有交互式艺术家处理该事件,则会在画布上调用以下通知:

  • on_press(自我,事件)

  • on_left_click(自我,事件)

  • on_middle_click(自我,事件)

  • on_right_click(自我,事件)

  • on_context_click(自我,事件)

  • on_key_up(自我,事件)

  • on_key_down(自我,事件)

以下函数(如果存在)可用于修改交互对象的行为:

  • press_filter(self,event) # 确定对象是否希望将按下事件路由到它

  • handle_unpicked_cursor() # 对象可以使用它来设置光标,因为光标在取消选中时经过对象。

支持多个画布,为每个画布维护一个拖动锁定、运动通知器和一个全局“启用”标志。通过在调整大小期间按住 shift 键支持固定纵横比调整大小。

已知问题:

  • 在选择/拖动操作期间不服从 Zorder。由于使用了 blit 技术,我不相信这可以解决。我能想到的唯一方法是搜索所有 zorder 大于我的艺术家,将它们全部设置为动画,然后在每次拖动刷新期间将它们全部重绘在顶部。这可能很慢;需要尝试。

  • mixin 仅适用于 wx 后端,原因有两个:1) 游标是硬编码的,2) 调用 wx.GetMousePosition() 通过让每个后端提供这些东西,这两个缺点都得到了合理的解决。

向后兼容性#

向后兼容没有问题,尽管一旦到位,废弃一些现有的交互功能(如legend.draggable())是合适的

替代方案#

据我所知没有。