Matplotlib has a feature where if you hold down the "x" or "y" keys it constrains panning or zooming to the corresponding axis.
Is there a way to cause this to be the default? For some reason my CPU does not allow touchpad movement when a letter key is held down. And I only want the x-axis to be pan/zoomed, not the y-axis.
edit: found the pan/zoom function at https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/axes.py#L3001
which contains an internal function format_deltas
. But I have no idea how to override the Axes class with a subclass when Axes objects are created automatically from Figure objects.
Matplotlib automatically arrives at the minimum and maximum values of variables to be displayed along x, y (and z axis in case of 3D plot) axes of a plot. However, it is possible to set the limits explicitly by using set_xlim() and set_ylim() functions.
It is possible to use your own axes class. In your case you can inherit from matplotlib.axes.Axes
and change the drag_pan
method to always act as though the 'x' key is being pressed. However the zooming doesn't seem to be defined in that class. The following will only allow x axis panning:
import matplotlib
import matplotlib.pyplot as plt
class My_Axes(matplotlib.axes.Axes):
name = "My_Axes"
def drag_pan(self, button, key, x, y):
matplotlib.axes.Axes.drag_pan(self, button, 'x', x, y) # pretend key=='x'
matplotlib.projections.register_projection(My_Axes)
figure = plt.figure()
ax = figure.add_subplot(111, projection="My_Axes")
ax.plot([0, 1, 2], [0, 1, 0])
plt.show()
For the zooming, you may have to look at the toolbar control itself. The NavigationToolbar2 class has the drag_zoom
method which seems to be what's relevant here, but tracking down how that works is quickly complicated by the fact that the different backends all have their own versions (e.g. NavigationToolbar2TkAgg
edit
You can monkeypatch the desired behaviour in:
import types
def press_zoom(self, event):
event.key='x'
matplotlib.backends.backend_tkagg.NavigationToolbar2TkAgg.press_zoom(self,event)
figure.canvas.toolbar.press_zoom=types.MethodType(press_zoom, figure.canvas.toolbar)
You could do it properly and make a subclass of the toolbar, but you have to then create instances of Figure, FigureCanvas and your NavigationToolbar and put them in a Tk app or something. I don't think there's a really straightforward way to just use your own toolbar with the simple plotting interface.
simonb's approach worked but I had to tweak it for the press_zoom
behavior, so that it keeps the press_zoom
method a feature of the class, not the instance, but I added a hook to fixup the per-instance behavior.
import types
def constrainXPanZoomBehavior(fig):
# make sure all figures' toolbars of this class call a postPressZoomHandler()
def overrideZoomMode(oldZoom, target):
def newZoom(self, event):
oldZoom(self, event)
if hasattr(self, 'postPressZoomHandler'):
self.postPressZoomHandler()
return newZoom
def overrideToolbarZoom(fig, methodname, functransform, *args):
toolbar = fig.canvas.toolbar
oldMethod = getattr(toolbar.__class__, methodname)
newMethod = functransform(oldMethod, toolbar, *args)
setattr(toolbar.__class__, methodname, newMethod)
overrideToolbarZoom(fig, 'press_zoom', overrideZoomMode)
# for this specific instance, override the zoom mode to 'x' always
def postPressZoomHandler(self):
self._zoom_mode = 'x'
fig.canvas.toolbar.postPressZoomHandler = types.MethodType(postPressZoomHandler, fig.canvas.toolbar)
return fig
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With