Title: tkinter variable classes don't link to widget if matplotlib's set_cmap() function is called before the tkinter GUI is instantiated
Type: behavior Stage: resolved
Components: Tkinter Versions: Python 3.9, Python 3.8, Python 3.7
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: amiraliemami, terry.reedy
Priority: normal Keywords:

Created on 2019-09-27 13:20 by amiraliemami, last changed 2019-09-27 21:56 by terry.reedy. This issue is now closed.

File name Uploaded Description Edit
tk and plt amiraliemami, 2019-09-27 13:20 simple demonstrative program in Python 3.6.8
Messages (2)
msg353359 - (view) Author: Amir Emami (amiraliemami) Date: 2019-09-27 13:20
TkInter variable classes don't link to a widget (tested on Checkbutton and Scale) if matplotlib.pyplot.set_cmap() function is called before the tkinter.Tk() call which instantiates the root of a TkInter GUI. There is no problem if it is called after this, though.

Simple example with checkbox attached below:

### Test program start ##############

import matplotlib.pyplot as plt
import tkinter as tk

plt.set_cmap('viridis') # <--- when placed here, breaks the variable
root = tk.Tk()
#plt.set_cmap('viridis') # <--- when placed here, everything is fine

# creation of variable class and widget
var = tk.BooleanVar()
tk.Checkbutton(root, variable=var).pack()

# for printing result
def on_click():
tk.Button(root, text="Print State to Console", command=on_click).pack()

msg353421 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2019-09-27 21:56
You neglected to state the observation that led to the conclusion of 'not linked'.  Using 3.8 on Win10, I replaced "plt.set_cmap('x')" with "tk.Tk()".  Then, clicking the button prints 'False' even when the checkbutton is checked.  After either removing 'tk.Tk()' *or* changing 'BooleanVar()' to 'BooleanVar(root)', button clicks print 'True' when the checkbutton is checked.

Explanation of what I see: tkinter has attribute tkinter._default_root initialized to None.  By default, this is rebound to the *first* root created by an internal or user tkinter.Tk() call.  Barring exceptional circumstances, one should either always use the default root and never create and pass a named root *or* never use the default one and create a named root and always pass it.  Your program is buggy in using the default root for the var and the named root for the buttons.  When the two are different, the expected linkage does not work.

I assume that you see the same failure with the code you posted and the same fix after (re)moving the .set_cmap call.  So I am further assuming that set_cmap somehow results in a default root being created and that fixing the buggy BooleanVar call will also fix things.

To test the set_cmap assumption, add "print(tk._default_root)" *before*  "root = tk.Tk()".  Do you see 'None' or '.'?  Does adding 'root' to the var call fix the link?  If you seen 'None' and the link still does not work, then 'set_cmap' must be affecting tkinter some other way, which would likely be a 3rd party bug in that function or pyplot.
Date User Action Args
2019-09-27 21:56:04terry.reedysetstatus: open -> closed

versions: + Python 3.7, Python 3.8, Python 3.9, - Python 3.6
nosy: + terry.reedy

messages: + msg353421
resolution: not a bug
stage: resolved
2019-09-27 13:20:38amiraliemamicreate