Matplotlib подключается к событиям home/back/forward button

Кто-нибудь знает, как "получить" события "домой", "назад" и "вперед" из рисунка matplotlib?

Мне нужны события для вызова некоторых из моих функций, так что мои графики корректно ведут себя при нажатии этой кнопки, т.е. поведение по умолчанию не делает то, что мне нужно делать

Matplotlib предполагает, что базовый набор данных является постоянным, и все, что ему нужно, это reset пределы оси x/y и их замена для этих кнопок - к сожалению, это предположение неверно для моего случая - у меня есть стек данных, который должен быть вытолкнут и выскочил, когда эти события кнопки запускаются

Ответ 1

Matplotlib не предоставляет событие "домой", "назад" или "вперед".

Чтобы добавить обратный вызов, который будет вызываться с помощью события "home", "back" или "forward", общий подход заключается в подклассе базы данных matplotlib.
Но я не сторонник такого подхода. Я думаю, что у него две минусы:

  • Если вы хотите использовать разные серверы, вы должны подклассифицировать каждый из них.
  • Развертывание собственного бэкэнда вне matplotlib не является тривиальным. Ваш сервер должен быть модулем, который должен находиться в PYTHONPATH.

Так как ни один из backend, предоставляемый matplotlib, не отменяет методы NavigationToolbar2 home, back и forward. Я предпочитаю более лаконичный подход, основанный на обезьянах.
Например, вы можете заменить NavigationToolbar2 home на свой собственный метод.

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()

Ответ 2

Я не знаю, как это сделать. Но когда вы используете сервер 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 в качестве backend не является для вас вариантом, мы могли бы попытаться сделать что-то подобное для других бэкэндов.

Ответ 3

Если вам удастся просто вызвать некоторую функцию всякий раз, когда оси x или y будут изменены, самым простым взломом будет привязка к событиям xlim_changed и ylim_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> и переопределить методы forward, back и home. Вам все равно нужно выяснить, как включить новый класс панели инструментов в зависимости от конкретного используемого вами бэкэнд.

Если вы хотите реализовать какой-то пользовательский элемент управления "вперед/назад", который не имеет ничего общего с установкой пределов оси, вам, вероятно, будет лучше использовать widgets.