Here's a way to do this without referring to a specific backend (i.e. it should be portable). The idea is that matplotlib defines a somewhat vague interface for backends to implement. This interface is the class NavigationToolbar2
below (github source; possible linux source directory: /usr/lib/python3/dist-packages/matplotlib/backend_bases.py). This interface uses a _nav_stack
object of type Stack
from cbook
. This stack keeps information about different panning information, and when something changes the toolbar calls a function _update_view
and redraws the canvas. By creating our own Stack
, supplying (a proxy to) it to the toolbar, and overwriting _update_view
, we can make the toolbar do what we'd like.
import matplotlib.backend_bases
import matplotlib.pyplot as plt
from numpy.random import random
# this is the data structure is used by NavigationToolbar2
# to switch between different pans. We'll make the figure's
# toolbar hold a proxy to such an object
from matplotlib.cbook import Stack
class StackProxy:
def __init__(self,stack):
self._stack = stack
def __call__(self):
return self._stack.__call__()
def __len__(self):
return self._stack.__len__()
def __getitem__(self,ind):
return self._stack.__getitem__(ind)
def nop(self): pass
# prevent modifying the stack
def __getattribute__(self,name):
if name == '_stack':
return object.__getattribute__(self,'_stack')
if name in ['push','clear','remove']:
return object.__getattribute__(self,'nop')
else:
return object.__getattribute__(self._stack,name)
stack = Stack()
for data in [[random(10),random(10)] for _ in range(5)]:
stack.push(data)
def redraw(*args):
plt.clf()
plt.scatter(*stack()) # stack() returns the currently pointed to item
plt.gcf().canvas.draw()
fig = plt.gcf()
toolbar = fig.canvas.toolbar
toolbar._update_view = redraw.__get__(toolbar)
stackProxy = StackProxy(stack)
toolbar._nav_stack = stackProxy
redraw()
plt.show()
Previously, I was modifying some base classes of the buttons, but since then I've learned about some object oriented techniques of python and found this to be a much better solution.