Denny
Denny

Reputation: 225

(Python) My slider cannot work in FigureCanvasTkAgg

I try to design a simple slider in the following environment; however, it cannot work

Note: I use Jupyter Notebook, so I utilized FigureCanvasTkAgg and TkAgg.

Note: I referred to the following great discussion; however, it still cannot work.
Python: Embed a matplotlib plot with slider in tkinter properly

from tkinter import *
import tkinter.ttk as ttk
import matplotlib
import matplotlib.pyplot as plt
%matplotlib widget
from matplotlib.widgets import Slider
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
matplotlib.use('TkAgg')

root = Tk()
root.title('TEST')
root.geometry("800x800")

def plot_noise():
    fig = plt.Figure()                       
    canvas = FigureCanvasTkAgg(fig, root)     
    canvas.get_tk_widget().grid(row=6, column=0, columnspan=3, rowspan=3, sticky=W+E+N+S, padx=0, pady=0)  
    slider_bar = fig.add_axes([0.12, 0.1, 0.78, 0.03])
    slider_de = matplotlib.widgets.Slider(slider_bar, 's_bar', 0, 124, valinit=20)

ttk.Label(root,text = "Push the Button", font=('Arial', 25)).grid(column=0, row=0, ipadx=5, pady=5, sticky=W+N)  
resultButton = ttk.Button(root, text = 'show', command = plot_noise)
resultButton.grid(column=0, row=1, pady=15, sticky=W)

root.mainloop()

However, the slider cannot work. I mean I cannot move the slider (no error pops out.)

How to fix that? Thanks!

enter image description here

Upvotes: 1

Views: 174

Answers (1)

Thingamabobs
Thingamabobs

Reputation: 8042

In the source code I have found your issue:

""" The base class for constructing Slider widgets. Not intended for direct usage. For the slider to remain responsive you must maintain a reference to it. """

The problem is that your Slider get garbage collected. You can prove that by:

    global slider_de
    slider_bar = fig.add_axes([0.12, 0.1, 0.78, 0.03])
    slider_de = matplotlib.widgets.Slider(slider_bar, 's_bar', 0, 124, valinit=20)

Also see the report of this bug and the given explaination in the docs:

The canvas retains only weak references to instance methods used as callbacks. Therefore, you need to retain a reference to instances owning such methods. Otherwise the instance will be garbage-collected and the callback will vanish.

and the reason for this architecture is also found in the source:

In practice, one should always disconnect all callbacks when they are no longer needed to avoid dangling references (and thus memory leaks). However, real code in Matplotlib rarely does so, and due to its design, it is rather difficult to place this kind of code. To get around this, and prevent this class of memory leaks, we instead store weak references to bound methods only, so when the destination object needs to die, the CallbackRegistry won't keep it alive.

Upvotes: 1

Related Questions