Skip to content

input() caused _tkinter.TclError: invalid command name XXX after plot.close() #17104

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
davidhcefx opened this issue Apr 11, 2020 · 9 comments
Closed

Comments

@davidhcefx
Copy link

Bug report

Bug summary

By calling the built-in input() function after closing the plot within an animation object, I got a Tkinter exception.

Code for reproduction

import matplotlib.pyplot as plt
import matplotlib.animation as animation

fig, ax = plt.subplots()
graph, = ax.plot([], [])
def update_plt(t):
	print(t)
	graph.axes.plot([1,2], [4, t])
	if t == 4:
		plt.close()
	return graph,

ani = animation.FuncAnimation(fig, update_plt, [r for r in range(10)],
							blit=False, interval=500, repeat=False)
plt.show()
x = input()  # <-- comment out, no exception.
print('Done.')

Actual outcome

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\davidhcefx\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 1883, in __call__
    return self.func(*args)
  File "C:\Users\davidhcefx\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 804, in callit
    func(*args)
  File "C:\Users\davidhcefx\AppData\Local\Programs\Python\Python38\lib\site-packages\matplotlib\backends\_backend_tk.py", line 270, in idle_draw
    self.draw()
  File "C:\Users\davidhcefx\AppData\Local\Programs\Python\Python38\lib\site-packages\matplotlib\backends\backend_tkagg.py", line 10, in draw
    _backend_tk.blit(self._tkphoto, self.renderer._renderer, (0, 1, 2, 3))
  File "C:\Users\davidhcefx\AppData\Local\Programs\Python\Python38\lib\site-packages\matplotlib\backends\_backend_tk.py", line 76, in blit
    photoimage.blank()
  File "C:\Users\davidhcefx\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 4065, in blank
    self.tk.call(self.name, 'blank')
_tkinter.TclError: invalid command name "pyimage10"

Expected outcome

No exception regarding Tkinter been thrown.

Matplotlib version

  • Operating system: Windows 10
  • Matplotlib version: 3.2.1
  • Matplotlib backend (print(matplotlib.get_backend())): TkAgg
  • Python version: 3.8.2
  • Other libraries: -

I installed matplotlib via python -m pip install matplotlib.

@anntzer
Copy link
Contributor

anntzer commented Apr 12, 2020

Looks like we need something like

diff --git i/lib/matplotlib/backends/_backend_tk.py w/lib/matplotlib/backends/_backend_tk.py
index 600722dfc..6df556c7f 100644
--- i/lib/matplotlib/backends/_backend_tk.py
+++ w/lib/matplotlib/backends/_backend_tk.py
@@ -218,8 +218,11 @@ class FigureCanvasTk(FigureCanvasBase):
         # to the window and filter.
         def filter_destroy(event):
             if event.widget is self._tkcanvas:
+                self._destroying = True
                 self._master.update_idletasks()
                 self.close_event()
+
+        self._destroying = False
         root.bind("<Destroy>", filter_destroy, "+")
 
         self._master = master
@@ -253,7 +256,8 @@ class FigureCanvasTk(FigureCanvasBase):
 
         def idle_draw(*args):
             try:
-                self.draw()
+                if not self._destroying:
+                    self.draw()
             finally:
                 self._idle = True

(Basically, destroy() is careful to cancel the last _idle_callback, but doesn't prevent the animation machinery to further register more _idle_callbacks after that. Adding a _destroying flag to completely cancel any new callbacks is similar to what's already being done for gtk and qt.)

Brownie points to whoever takes this patch, checks that it works, and turns it into a proper PR.

davidhcefx added a commit to davidhcefx/matplotlib that referenced this issue Apr 17, 2020
matplotlib#17104 
Tested on
- OS: Windows 10
- Matplotlib backend: TkAgg
- Python: 3.7.7
@davidhcefx
Copy link
Author

@anntzer
Hi,

I have built matplotlib and tested the patch you provided works on my machine. When creating a pull request, however, I was confused by the following two lines within the pull-request template:

- [ ] Has Pytest style unit tests
- Do not create the PR out of master, but out of a separate branch.

  1. Do I need to leave the option "Pytest style unit test" unchecked?
  2. Should I create a pull request, from my repo to matplotlib/matplotlib master branch? If not, how should I create a pull request properly? (Or is it that I have to push to v.3.2.x instead?)

Thanks.

@brunobeltran
Copy link
Contributor

Hi @davidhcefx. First, thanks for the interest in contributing! To answer your questions

  1. Preferably, you would create a test in lib/matplotlib/tests/test_backend_tk.py that fails if you run it without your patch, and passes with your patch in place. The most pared-down version possible of your code example from the original bug report is usually sufficient. Make sure to also leave a couple of comments about what the test is looking for!
  2. Yes, create a pull request from your feature branch (i.e. from davidhcefx/matplotlib, looks like you called the branch patch1, into the master branch of matplotlib/matplotlib).

@tacaswell
Copy link
Member

@davidhcefx Did you open a PR?

While we do try to get tests on everything, I do not think we should hold merging this on reproducing the race condition that leads to this on CI.

davidhcefx added a commit to davidhcefx/matplotlib that referenced this issue May 15, 2020
Idle callbacks will trigger exceptions after canvas been destroyed.
Bug matplotlib#17104
davidhcefx added a commit to davidhcefx/matplotlib that referenced this issue May 15, 2020
@davidhcefx
Copy link
Author

@tacaswell I have just opened a PR. Sorry for the delay.

@QuLogic
Copy link
Member

QuLogic commented Jun 15, 2020

This is fixed on master and v3.2.x, by #17391, I believe, while fixing a different issue.

@mercerb
Copy link

mercerb commented Oct 26, 2020

Is anyone else still having this issue? I have matplotlib version 3.3.2, and every time I close a figure window, I get the _tkinter.TclError: invalid command name "pyimage10" error.

@tacaswell
Copy link
Member

@mercerb Can you open a new issue with system + version details?

We have in the past seen behavior that depends on both the OS and tk versions...

@mercerb
Copy link

mercerb commented Oct 26, 2020

@mercerb Can you open a new issue with system + version details?
We have in the past seen behavior that depends on both the OS and tk versions...

Yep makes sense, but I actually just realized what the issue was. I had a while plot._running: loop, and I needed to use an on_close() handler to set plot._running to False. The error message wasn't clear, but it went away after I did that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants