在matplotlib中处理主页/返回/前进按钮事件

19 投票
3 回答
10371 浏览
提问于 2025-04-17 16:00

有没有人知道怎么从matplotlib图形中获取“主页”、“后退”和“前进”按钮的事件?

我需要这些事件来调用我的一些函数,这样当按下这些按钮时,我的图表才能正常工作,也就是说,默认的行为并不能满足我的需求。

matplotlib假设底层的数据集是固定的,它只需要重置x/y轴的范围并重新绘制图形来应对这些按钮的操作——但不幸的是,这个假设在我的情况下并不成立——我有一个数据堆栈,需要在这些按钮事件触发时进行推入和弹出。

3 个回答

7

我不知道有没有一种不依赖后台的解决方案来解决这个问题。不过,如果你使用的是Qt4Agg这个后台,你可以试试这样做:

import matplotlib
matplotlib.use("Qt4Agg")
import pylab as p

def home_callback():
    print "home called"

def back_callback():
    print "back called"

def forward_callback():
    print "forward called"

p.ion()
p.plot(p.random((10)))

fm = p.get_current_fig_manager()

fm.toolbar.actions()[0].triggered.connect(home_callback)
fm.toolbar.actions()[1].triggered.connect(back_callback)
fm.toolbar.actions()[2].triggered.connect(forward_callback)

首先,我获取当前的图形管理器,这样我就可以访问它的工具栏。然后,我可以把其他的回调函数连接到它的操作上。

如果你不能使用QT4Agg作为后台,我们可以尝试为其他后台做类似的事情。

7

如果你想在x轴或y轴大小改变时简单地调用某个函数,最简单的方法就是绑定到xlim_changedylim_changed这两个事件上。这些事件是由你的坐标轴生成的。例如:

   def on_xlim_change(*args):
          print "do your pushing and popping here..."
   ax = gca()
   ax.callbacks.connect('xlim_changed',on_xlim_change)

这个回调函数会在你按下前进、后退或主页键时执行,同时在你使用平移或缩放工具时也会执行(至少在WX和GTK这两种后端中是这样的)。不过,它是在matplotlib已经完成了坐标轴的常规缩放之后才执行的。

如果你真的想直接访问这些按钮的回调函数,那我觉得没有简单的方法可以不依赖于后端,因为事件处理的方式会根据你使用的后端不同而有所不同。我认为基本的方法是创建一个matplotlib.backends.backend_<name>.NavigationToolbar2<name>的子类,并重写forwardbackhome这几个方法。你还需要根据你使用的具体后端,弄清楚如何将你新的工具栏类整合进去。

如果你想实现一些与设置坐标轴范围没有太大关系的自定义“前进/后退”控制,使用小部件可能会更好。

27

Matplotlib并没有提供“主页”、“后退”或“前进”按钮的事件。

如果想要添加一个回调函数,让它在点击“主页”、“后退”或“前进”按钮时被调用,通常的做法是创建一个matplotlib后端的子类。
不过,我不太喜欢这种做法。我觉得有两个缺点:

  1. 如果你想使用不同的后端,就得为每个后端都创建一个子类。
  2. 在matplotlib之外部署你自己的后端并不简单。你的后端必须是一个模块,并且要在PYTHONPATH中。

因为matplotlib提供的后端都没有重写NavigationToolbar2homebackforward方法,所以我更喜欢一种更简洁的猴子补丁(monkey-patch)方法。
比如,你可以用自己的方法替换掉NavigationToolbar2home

import matplotlib.pyplot as plt
from matplotlib.backend_bases import NavigationToolbar2

home = NavigationToolbar2.home

def new_home(self, *args, **kwargs):
    print 'new home'
    home(self, *args, **kwargs)

NavigationToolbar2.home = new_home

fig = plt.figure()
plt.text(0.35, 0.5, 'Hello world!', dict(size=30))
plt.show()

我们甚至可以模仿matplotlib的mpl_connect风格。

import matplotlib.pyplot as plt
from matplotlib.backend_bases import NavigationToolbar2, Event

home = NavigationToolbar2.home

def new_home(self, *args, **kwargs):
    s = 'home_event'
    event = Event(s, self)
    event.foo = 100
    self.canvas.callbacks.process(s, event)
    home(self, *args, **kwargs)

NavigationToolbar2.home = new_home

def handle_home(evt):
    print 'new home'
    print evt.foo

fig = plt.figure()
fig.canvas.mpl_connect('home_event', handle_home)
plt.text(0.35, 0.5, 'Hello world!', dict(size=30))
plt.show()

撰写回答