Overview
I am in the process of embedding a Matplotlib plot in a Tkinter window. I need to use the Matplotlib event handler functions (described here). When run as a standalone Matplotlib figure, I get the correct behavior: the event handlers perform their correct function on the correct user action. But when embedding in a Tkinter window, the Matplotlib event handlers are no longer being called.
Expected Behavior
The Matplotlib event handler should be called when the figure is embedded in a Tkinter window.
Current Behavior
The Matplotlib event handler is not being called.
Minimal Code Snippet
Without Tkinter
import matplotlib.pyplot as plt
def onpick(event):
print("You selected the line!")
if __name__=='__main__':
### MATPLOTLIB SETUP ###
xs = [0,1,2] #x-values of the graph
ys = [4,3,2] #y-values of the graph
fig, ax = plt.subplots(1)
ax.plot(xs, ys, picker=True)
fig.canvas.mpl_connect('pick_event', onpick)
plt.show()
When this code is run, you can select the line on the plot and the onpick
method is called, printing the text to stdout
. This is the desired output.
Embedded in Tkinter
import tkinter
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
def onpick(event):
print("You selected the line!")
if __name__=='__main__':
### MATPLOTLIB SETUP ###
xs = [0,1,2] #x-values of the graph
ys = [4,3,2] #y-values of the graph
fig, ax = plt.subplots(1)
ax.plot(xs, ys, picker=True)
fig.canvas.mpl_connect('pick_event', onpick)
### TKINTER SETUP ###
root = tkinter.Tk()
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.draw()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
tkinter.mainloop()
When this code is run and you try to click on the line, the text is never printed meaning the onpick
method is never being called.
Versions
python
: 3.6.1matplotlib
: 3.3.4tkinter
: 8.6.6
CodePudding user response:
The event listeners of the Matplotlib Figure
object cannot be called when embedded in Tkinter. Instead, you have to add the listeners to the FigureCanvasTkAgg
(or similar) object. So a working example built on the previous minimal example would be:
import tkinter
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
def onpick(event):
print("You selected the line!")
if __name__=='__main__':
### MATPLOTLIB SETUP ###
xs = [0,1,2] #x-values of the graph
ys = [4,3,2] #y-values of the graph
fig, ax = plt.subplots(1)
ax.plot(xs, ys, picker=True)
#plt.show()
### TKINTER SETUP ###
root = tkinter.Tk()
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.draw()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
canvas.mpl_connect("pick_event", onpick) # Add the listener using this command
tkinter.mainloop()