Home > Software engineering >  Matplotlib Event Handlers not being Called when Embedded in Tkinter
Matplotlib Event Handlers not being Called when Embedded in Tkinter

Time:04-13

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.1
  • matplotlib : 3.3.4
  • tkinter : 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()
  • Related