You must call plt.gcf().canvas.mpl_connect('key_press_event',ontype) before plt.show(). In non-interactive mode, the execution waits at plt.show() until the plot-window is closed.
import pylab as plt
# event definition
def ontype(event):
if event.key == '1':
print "1"
elif event.key == '2':
print "2"
elif event.key == '3':
print "3"
# main program
plt.plot([1,6,3,8,7])
plt.gcf().canvas.mpl_connect('key_press_event',ontype)
plt.show()
Alternatively, replace in your sample plt.show() to plt.ion(), which enables interactive mode. But it depends on your specific needs which solution you prefer.
Edit
New example using Tkinter
import random
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
try:
import Tkinter as Tk
except ImportError:
import tkinter as Tk
import tkMessageBox
class PlotClassifier(Tk.Tk):
def __init__(self, plot_generator, arguments, classes, classification_callback, *args, **kwargs):
Tk.Tk.__init__(self, *args, **kwargs)
self.title("Plot classifier, working on %i plots" % len(arguments))
#self.label = Tk.Label(text="Plot classifier, working on %i plots" % len(arguments))
#self.label.pack(padx=10, pady=10)
self._plot_generator = plot_generator
self._arguments = arguments
self._classes = [str(x) for x in classes]
self._classification_callback = classification_callback
self._setup_gui()
def _setup_gui(self):
#self.columnconfigure(0, minsize=100, weight=2)
#self.columnconfigure(1, minsize=500, weight=8)
f = Figure()
self._ax = f.add_subplot(111)
buttons_frame = Tk.Frame(self)
buttons_frame.pack(side=Tk.TOP, fill=Tk.BOTH, expand=True)
buttons_class = []
for i, cls in enumerate(self._classes):
buttons_class.append(Tk.Button(master=buttons_frame, text=cls,
command=lambda x=i: self.button_classification_callback(self._current_args, x)))
buttons_class[-1].pack(side=Tk.LEFT)
button_quit = Tk.Button(master=buttons_frame, text='Quit', command=self.destroy)
button_quit.pack(side=Tk.RIGHT) #.grid(row=0,column=0)
self._canvas = FigureCanvasTkAgg(f, master=self)
self._canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) #.grid(row=0, column=1, rowspan=3) #
self._canvas.show()
toolbar = NavigationToolbar2TkAgg( self._canvas, self )
toolbar.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) #.grid(row=3, column=1) #
toolbar.update()
def button_classification_callback(self, args, class_idx):
self._classification_callback(args, self._classes[class_idx])
self.classify_next_plot()
def classify_next_plot(self):
try:
self._current_args = self._arguments.pop(0)
self._ax.cla()
self._plot_generator(self._ax, *self._current_args)
self._canvas.draw()
except IndexError:
tkMessageBox.showinfo("Complete!", "All plots were classified")
self.destroy()
def create_plot(ax, factor):
ax.plot([(i*factor) % 11 for i in range(100)])
def announce_classification(arguments, class_):
print arguments, class_
if __name__ == "__main__":
classes = ["Class %i"%i for i in range(1, 6)]
arguments_for_plot = [[random.randint(1,10)] for x in range(10)]
root = PlotClassifier(create_plot, arguments_for_plot, classes, classification_callback=announce_classification)
root.after(50, root.classify_next_plot)
root.mainloop()
The class takes as arguments:
* a callback to create each plot
* a list of lists of arguments for each plot to generate (might each be an empty list)
* a list of class-names. For each class, a button is created
* a callback that is called each time a classification has been performed
Any feedback would be appreciated.
*EDIT 2 *
For your comment, a slightly modified version. For every iteration of the loop, a new window is opened
import random
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
try:
import Tkinter as Tk
except ImportError:
import tkinter as Tk
import tkMessageBox
class PlotClassifier(Tk.Tk):
def __init__(self, plot_generator, arguments, classes, *args, **kwargs):
Tk.Tk.__init__(self, *args, **kwargs)
self.title("Plot classifier")
self._plot_generator = plot_generator
self._arguments = arguments
self._classes = [str(x) for x in classes]
self.class_ = None
self._setup_gui()
def _setup_gui(self):
#self.columnconfigure(0, minsize=100, weight=2)
#self.columnconfigure(1, minsize=500, weight=8)
f = Figure()
self._ax = f.add_subplot(111)
buttons_frame = Tk.Frame(self)
buttons_frame.pack(side=Tk.TOP, fill=Tk.X, expand=True)
buttons_class = []
for i, cls in enumerate(self._classes):
buttons_class.append(Tk.Button(master=buttons_frame, text=cls,
command=lambda x=i: self.button_classification_callback(x)))
buttons_class[-1].pack(side=Tk.LEFT)
button_quit = Tk.Button(master=buttons_frame, text='Quit', command=self.destroy)
button_quit.pack(side=Tk.RIGHT) #.grid(row=0,column=0)
self._canvas = FigureCanvasTkAgg(f, master=self)
self._canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) #.grid(row=0, column=1, rowspan=3) #
self._canvas.show()
toolbar = NavigationToolbar2TkAgg( self._canvas, self )
toolbar.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) #.grid(row=3, column=1) #
toolbar.update()
def button_classification_callback(self, class_idx):
self.class_ = self._classes[class_idx]
self.destroy()
def classify_plot(self):
self._ax.cla()
self._plot_generator(self._ax, *self._arguments)
self._canvas.draw()
self.mainloop()
return self.class_
def create_plot(ax, factor):
ax.plot([(i*factor) % 11 for i in range(100)])
if __name__ == "__main__":
classes = ["Class %i"%i for i in range(1, 6)]
arguments_for_plot = [[random.randint(1,10)] for x in range(10)]
for args in arguments_for_plot:
classifier = PlotClassifier(create_plot, args, classes)
class_ = classifier.classify_plot()
print args, class_
if class_ is None:
break
This helps to fit into your own for-loop, but you still have to give a function to do the plotting after the GUI was created.