Python Matplotlib工具栏源码探析三之添加、删除自定义工具项的案例详解

Cora
Cora
发布时间:2026-10-15 | 3人浏览过
原创

本文深入解析Matplotlib工具栏源码,重点介绍如何添加和删除自定义工具项。通过官方案例详解ToolManager模式,展示基于ToolBase和ToolToggleBase创建自定义工具项的方法,包括定义触发、启用和禁用动作,以及将工具项添加到工具栏管理器和具体工具栏的标准流程。

在上一篇关于Matplotlib工具栏源码探析二的文章中,我们探讨了工具栏内置工具项的管理机制。然而,在实际开发场景中,往往需要扩展功能,添加自定义的工具项。官方文档提供了一个参考案例https://matplotlib.org/gallery/user_interfaces/toolmanager_sgskip.html,该案例主要基于matplotlib.backend_managers.ToolManager类来实现,其核心思想是采用工具栏管理器模式。

官方案例解析

接下来,我们将对官方提供的案例中的关键代码进行逐行注释和说明。


import matplotlib.pyplot as plt
# 设置工具栏使用工具栏管理器模式
plt.rcParams['toolbar'] = 'toolmanager'
# 导入工具项的基类ToolBase和ToolToggleBase
from matplotlib.backend_tools import ToolBase, ToolToggleBase

# 因为工具项必须以类的形式添加,所以创建自定义基本工具项类,基类为ToolBase
class ListTools(ToolBase):
 # 该工具项的功能为列出工具栏管理器管理的所有工具项
 """List all the tools controlled by the `ToolManager`."""
 # 设置默认快捷键和工具项描述
 default_keymap = 'm'
 description = 'List Tools'
 
 # 定义工具项被触发时的动作
 def trigger(self, *args, **kwargs):
  print('_' * 80)
  print("{0:12} {1:45} {2}".format(
   'Name (id)', 'Tool description', 'Keymap'))
  print('-' * 80)
  # 获取工具栏管理器管理的所有工具项
  tools = self.toolmanager.tools
  # 输出各个工具项
  for name in sorted(tools):
   if not tools[name].description:
    continue
   keys = ', '.join(sorted(self.toolmanager.get_tool_keymap(name)))
   print("{0:12} {1:45} {2}".format(
    name, tools[name].description, keys))
  print('_' * 80)
  print("Active Toggle tools")
  print("{0:12} {1:45}".format("Group", "Active"))
  print('-' * 80)
  for group, active in self.toolmanager.active_toggle.items():
   print("{0:12} {1:45}".format(str(group), str(active)))

# 基于ToolToggleBase创建自定义切换式工具项,切换式工具项在触发时会在生效和失效两种状态之间切换
class GroupHideTool(ToolToggleBase):
 # 该工具项的功能为根据分组切换显示/隐藏数据元素
 """Show lines with a given gid."""
 # 设置默认快捷键和工具项描述
 default_keymap = 'G'
 description = 'Show by gid'
 default_toggled = True
 
 # 构造函数的参数gid为数据元素的分组
 def __init__(self, *args, gid, **kwargs):
  self.gid = gid
  super().__init__(*args, **kwargs)
 # 定义工具项生效时的方法
 def enable(self, *args):
  self.set_lines_visibility(True)
 # 定义工具项失效时的方法
 def disable(self, *args):
  self.set_lines_visibility(False)

 def set_lines_visibility(self, state):
  for ax in self.figure.get_axes():
   for line in ax.get_lines():
    if line.get_gid() == self.gid:
     line.set_visible(state)
  # 注意!在图像生成之后,修改图像中的元素必须重绘
  self.figure.canvas.draw()


fig = plt.figure()
# 注意通过gid属性可以为数据元素分组
plt.plot([1, 2, 3], gid='mygroup')
plt.plot([2, 3, 4], gid='unknown')
plt.plot([3, 2, 1], gid='mygroup')

# 将自定义的工具项添加添加到工具栏管理器,格式为 工具项名称 工具项类 其他参数
fig.canvas.manager.toolmanager.add_tool('List', ListTools)
fig.canvas.manager.toolmanager.add_tool('Show', GroupHideTool, gid='mygroup')

# 可以反复添加已存在的工具项
# Add an existing tool to new group `foo`.
# It can be added as many times as we want
fig.canvas.manager.toolbar.add_tool('zoom', 'foo')

# 删除工具项
# Remove the forward button
fig.canvas.manager.toolmanager.remove_tool('forward')

# 新添加到工具栏管理器的工具项还不能直接使用,需要通过toolbar对象添加到当前工具栏
# 如果不将自定义的工具项添加到工具栏管理器,直接使用toolbar对象添加则会报错
# 将自定义的工具项Show添加到内置的navigation组的特定位置(即组内第2个位置)
# To add a custom tool to the toolbar at specific location inside
# the navigation group
fig.canvas.manager.toolbar.add_tool('Show', 'navigation', 1)
#fig.canvas.manager.toolbar.add_tool('List', 'navigation', 2)
plt.show()

官方案例运行结果

当程序运行后,可以看到自定义的Show按钮处于激活状态,此时图表中的3条数据线全部显示。

如果点击Show按钮,使其处于非激活(失效)状态,那么属于mygroup组的两条线将不再显示。

需要注意的是,在案例代码中,List工具项虽然被添加到了工具栏管理器中,但并未被添加到具体的工具栏实例中,因此List工具项不会在工具栏界面上显示出来。不过,List工具项绑定的快捷键m依然有效。在界面上按下快捷键m后,控制台会输出相应的工具列表信息。


________________________________________________________________________________
Name (id) Tool description        Keymap
--------------------------------------------------------------------------------
List   List Tools         m
Show   Show by gid         G
allnav  Enable all axes toolmanager     a
back   Back to previous view       MouseButton.BACK, backspace, c, left
copy   Copy the canvas figure to clipboard   cmd+c, ctrl+c
fullscreen Toggle fullscreen mode      ctrl+f, f
grid   Toggle major grids       g
grid_minor Toggle major and minor grids
help   Print tool list, shortcuts and description f1
home   Reset original view       h, home, r
nav   Enable one axes toolmanager     1, 2, 3, 4, 5, 6, 7, 8, 9
pan   Pan axes with left mouse, zoom with right  p
quit   Quit the figure        cmd+w, ctrl+w, q
quit_all  Quit all figures
save   Save the figure        ctrl+s, s
subplots  Configure subplots
xscale  Toggle scale X axis       L, k
yscale  Toggle scale Y axis       l
zoom   Zoom to rectangle        o
________________________________________________________________________________
Active Toggle tools
Group  Active
--------------------------------------------------------------------------------
default  None
None   {'Show'}

总结

matplotlib支持两种类型的工具项:基本工具项(基类为ToolBase)和切换式工具项(基类为ToolToggleBase)。 对于基本工具项,关键在于定义trigger方法,该方法定义了当工具项被触发时执行的具体动作。 对于切换式工具项,则需要定义enable和disable方法,分别处理工具项生效和失效两种状态下的动作。如果这些方法涉及图像修改,务必注意调用重绘图像的逻辑。 最后,务必注意添加自定义工具项的正确流程:首先将自定义工具项注册到工具栏管理器(ToolManager),然后再将其添加到当前的工具栏(Toolbar)实例中。内置工具项之所以不需要手动添加到工具栏管理器,是因为它们在初始化时已经默认注册在管理器中。

至此,关于Matplotlib工具栏源码探析第三部分——添加与删除自定义工具项的详细介绍已完毕。如需了解更多Matplotlib工具栏相关内容,欢迎查阅本站往期文章或继续阅读后续系列。感谢大家的支持!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表