Skip to content

expose key press handler #717

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 10, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/users/navigation_toolbar.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ The ``Save`` button
``svg`` and ``pdf``.


.. _key-event-handling:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I think I would rather see these tags done like so:

.. _gallery_tags::
:key-event-handling:
:foo-tag:
:spam-tag:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nm, I had a brain fart and didn't realize it was a reference tag.


Navigation Keyboard Shortcuts
-----------------------------

Expand Down
8 changes: 8 additions & 0 deletions examples/user_interfaces/embedding_in_gtk2.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#from matplotlib.backends.backend_gtk import NavigationToolbar2GTK as NavigationToolbar
from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar

# implement the default mpl key bindings
from matplotlib.backend_bases import key_press_handler

win = gtk.Window()
win.connect("destroy", lambda x: gtk.main_quit())
Expand All @@ -40,5 +42,11 @@
vbox.pack_start(toolbar, False, False)


def on_key_event(event):
print('you pressed %s'%event.key)
key_press_handler(event, canvas, toolbar)

canvas.mpl_connect('key_press_event', on_key_event)

win.show_all()
gtk.main()
63 changes: 63 additions & 0 deletions examples/user_interfaces/embedding_in_qt4_wtoolbar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import sys
import numpy as np
from matplotlib.figure import Figure
from matplotlib.backend_bases import FigureManagerBase, key_press_handler
from PyQt4.QtCore import *
from PyQt4.QtGui import *

from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar


class AppForm(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
#self.x, self.y = self.get_data()
self.data = self.get_data2()
self.create_main_frame()
self.on_draw()

def create_main_frame(self):
self.main_frame = QWidget()

self.fig = Figure((5.0, 4.0), dpi=100)
self.canvas = FigureCanvas(self.fig)
self.canvas.setParent(self.main_frame)
self.canvas.setFocusPolicy( Qt.StrongFocus )
self.canvas.setFocus()

self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)

self.canvas.mpl_connect('key_press_event', self.on_key_press)

vbox = QVBoxLayout()
vbox.addWidget(self.canvas) # the matplotlib canvas
vbox.addWidget(self.mpl_toolbar)
self.main_frame.setLayout(vbox)
self.setCentralWidget(self.main_frame)

def get_data2(self):
return np.arange(20).reshape([4,5]).copy()

def on_draw(self):
self.fig.clear()
self.axes = self.fig.add_subplot(111)
#self.axes.plot(self.x, self.y, 'ro')
self.axes.imshow(self.data, interpolation='nearest')
#self.axes.plot([1,2,3])
self.canvas.draw()

def on_key_press(self, event):
print 'you pressed', event.key
# implement the default mpl key press events described at
# http://matplotlib.sourceforge.net/users/navigation_toolbar.html#navigation-keyboard-shortcuts
key_press_handler(event, self.canvas, self.mpl_toolbar)

def main():
app = QApplication(sys.argv)
form = AppForm()
form.show()
app.exec_()

if __name__ == "__main__":
main()
10 changes: 10 additions & 0 deletions examples/user_interfaces/embedding_in_tk.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@

from numpy import arange, sin, pi
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
# implement the default mpl key bindings
from matplotlib.backend_bases import key_press_handler


from matplotlib.figure import Figure

import sys
Expand Down Expand Up @@ -34,6 +38,12 @@
toolbar.update()
canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

def on_key_event(event):
print('you pressed %s'%event.key)
key_press_handler(event, canvas, toolbar)

canvas.mpl_connect('key_press_event', on_key_event)

def _quit():
root.quit() # stops mainloop
root.destroy() # this is necessary on Windows to prevent
Expand Down
204 changes: 111 additions & 93 deletions lib/matplotlib/backend_bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -1436,7 +1436,7 @@ def __init__(self, figure):
self.button_pick_id = self.mpl_connect('button_press_event',self.pick)
self.scroll_pick_id = self.mpl_connect('scroll_event',self.pick)
self.mouse_grabber = None # the axes currently grabbing mouse

self.toolbar = None # NavigationToolbar2 will set me
if False:
## highlight the artists that are hit
self.mpl_connect('motion_notify_event',self.onHilite)
Expand Down Expand Up @@ -2213,6 +2213,110 @@ def stop_event_loop_default(self):
self._looping = False


def key_press_handler(event, canvas, toolbar=None):
"""
Implement the default mpl key bindings for the canvas and toolbar
described at :ref:`key-event-handling`

*event*
a :class:`KeyEvent` instance
*canvas*
a :class:`FigureCanvasBase` instance
*toolbar*
a :class:`NavigationToolbar2` instance

"""
# these bindings happen whether you are over an axes or not
#if event.key == 'q':
# self.destroy() # how cruel to have to destroy oneself!
# return

if event.key is None:
return

# Load key-mappings from your matplotlibrc file.
fullscreen_keys = rcParams['keymap.fullscreen']
home_keys = rcParams['keymap.home']
back_keys = rcParams['keymap.back']
forward_keys = rcParams['keymap.forward']
pan_keys = rcParams['keymap.pan']
zoom_keys = rcParams['keymap.zoom']
save_keys = rcParams['keymap.save']
grid_keys = rcParams['keymap.grid']
toggle_yscale_keys = rcParams['keymap.yscale']
toggle_xscale_keys = rcParams['keymap.xscale']
all = rcParams['keymap.all_axes']

# toggle fullscreen mode (default key 'f')
if event.key in fullscreen_keys:
self.full_screen_toggle()

if toolbar is not None:
# home or reset mnemonic (default key 'h', 'home' and 'r')
if event.key in home_keys:
toolbar.home()
# forward / backward keys to enable left handed quick navigation
# (default key for backward: 'left', 'backspace' and 'c')
elif event.key in back_keys:
toolbar.back()
# (default key for forward: 'right' and 'v')
elif event.key in forward_keys:
toolbar.forward()
# pan mnemonic (default key 'p')
elif event.key in pan_keys:
toolbar.pan()
# zoom mnemonic (default key 'o')
elif event.key in zoom_keys:
toolbar.zoom()
# saving current figure (default key 's')
elif event.key in save_keys:
toolbar.save_figure()

if event.inaxes is None:
return

# the mouse has to be over an axes to trigger these
# switching on/off a grid in current axes (default key 'g')
if event.key in grid_keys:
event.inaxes.grid()
canvas.draw()
# toggle scaling of y-axes between 'log and 'linear' (default key 'l')
elif event.key in toggle_yscale_keys:
ax = event.inaxes
scale = ax.get_yscale()
if scale == 'log':
ax.set_yscale('linear')
ax.figure.canvas.draw()
elif scale == 'linear':
ax.set_yscale('log')
ax.figure.canvas.draw()
# toggle scaling of x-axes between 'log and 'linear' (default key 'k')
elif event.key in toggle_xscale_keys:
ax = event.inaxes
scalex = ax.get_xscale()
if scalex == 'log':
ax.set_xscale('linear')
ax.figure.canvas.draw()
elif scalex == 'linear':
ax.set_xscale('log')
ax.figure.canvas.draw()

elif (event.key.isdigit() and event.key!='0') or event.key in all:
# keys in list 'all' enables all axes (default key 'a'),
# otherwise if key is a number only enable this particular axes
# if it was the axes, where the event was raised
if not (event.key in all):
n = int(event.key)-1
for i, a in enumerate(canvas.figure.get_axes()):
# consider axes, in which the event was raised
# FIXME: Why only this axes?
if event.x is not None and event.y is not None \
and a.in_axes(event):
if event.key in all:
a.set_navigate(True)
else:
a.set_navigate(i==n)


class FigureManagerBase:
"""
Expand All @@ -2224,7 +2328,7 @@ class FigureManagerBase:
A :class:`FigureCanvasBase` instance

*num*
The figure nuamber
The figure number
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wasn't there a change that allowed for names for figures as well?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but this is converted from a string label to a number by the time it gets to the FigureManagerBase -- see pyplot.figure impl. So the docstring is correct here that this will be a number

https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/pyplot.py#L318

"""
def __init__(self, canvas, num):
self.canvas = canvas
Expand All @@ -2244,97 +2348,11 @@ def resize(self, w, h):
pass

def key_press(self, event):

# these bindings happen whether you are over an axes or not
#if event.key == 'q':
# self.destroy() # how cruel to have to destroy oneself!
# return

if event.key is None:
return

# Load key-mappings from your matplotlibrc file.
fullscreen_keys = rcParams['keymap.fullscreen']
home_keys = rcParams['keymap.home']
back_keys = rcParams['keymap.back']
forward_keys = rcParams['keymap.forward']
pan_keys = rcParams['keymap.pan']
zoom_keys = rcParams['keymap.zoom']
save_keys = rcParams['keymap.save']
grid_keys = rcParams['keymap.grid']
toggle_yscale_keys = rcParams['keymap.yscale']
toggle_xscale_keys = rcParams['keymap.xscale']
all = rcParams['keymap.all_axes']

# toggle fullscreen mode (default key 'f')
if event.key in fullscreen_keys:
self.full_screen_toggle()

# home or reset mnemonic (default key 'h', 'home' and 'r')
elif event.key in home_keys:
self.canvas.toolbar.home()
# forward / backward keys to enable left handed quick navigation
# (default key for backward: 'left', 'backspace' and 'c')
elif event.key in back_keys:
self.canvas.toolbar.back()
# (default key for forward: 'right' and 'v')
elif event.key in forward_keys:
self.canvas.toolbar.forward()
# pan mnemonic (default key 'p')
elif event.key in pan_keys:
self.canvas.toolbar.pan()
# zoom mnemonic (default key 'o')
elif event.key in zoom_keys:
self.canvas.toolbar.zoom()
# saving current figure (default key 's')
elif event.key in save_keys:
self.canvas.toolbar.save_figure()

if event.inaxes is None:
return

# the mouse has to be over an axes to trigger these
# switching on/off a grid in current axes (default key 'g')
if event.key in grid_keys:
event.inaxes.grid()
self.canvas.draw()
# toggle scaling of y-axes between 'log and 'linear' (default key 'l')
elif event.key in toggle_yscale_keys:
ax = event.inaxes
scale = ax.get_yscale()
if scale == 'log':
ax.set_yscale('linear')
ax.figure.canvas.draw()
elif scale == 'linear':
ax.set_yscale('log')
ax.figure.canvas.draw()
# toggle scaling of x-axes between 'log and 'linear' (default key 'k')
elif event.key in toggle_xscale_keys:
ax = event.inaxes
scalex = ax.get_xscale()
if scalex == 'log':
ax.set_xscale('linear')
ax.figure.canvas.draw()
elif scalex == 'linear':
ax.set_xscale('log')
ax.figure.canvas.draw()

elif (event.key.isdigit() and event.key!='0') or event.key in all:
# keys in list 'all' enables all axes (default key 'a'),
# otherwise if key is a number only enable this particular axes
# if it was the axes, where the event was raised
if not (event.key in all):
n = int(event.key)-1
for i, a in enumerate(self.canvas.figure.get_axes()):
# consider axes, in which the event was raised
# FIXME: Why only this axes?
if event.x is not None and event.y is not None \
and a.in_axes(event):
if event.key in all:
a.set_navigate(True)
else:
a.set_navigate(i==n)

"""
implement the default mpl key bindings defined at
:ref:`key-event-handling`
"""
key_press_handler(event, self.canvas, self.canvas.toolbar)

def show_popup(self, msg):
"""
Expand Down