pandastable icon indicating copy to clipboard operation
pandastable copied to clipboard

TclError when using pandastable with matplotlib figure

Open thawn opened this issue 4 years ago • 3 comments

I would like to use pandastable together with my own matplotlib figure. However, I get the following error: _tkinter.TclError: image "pyimage10" doesn't exist

here is a minimal code example that reproduces the error:

import tkinter
import pandas as pd
from pandastable import Table
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

fig = plt.figure()

root = tkinter.Tk()
pane = tkinter.Canvas(root)
pdframe = pd.DataFrame()
table = Table(pane, dataframe=pdframe, showtoolbar=False, showstatusbar=True)
table.show()
pane.pack()
root.mainloop()

without the line fig = plt.figure() the code works as expected

I was able to work around the problem by replacing root = tkinter.Tk() with root = tkinter.Toplevel(). See also this stackexchange question. However, this workaround causes other problems like the application not closing properly.

This seems to indicate, that matplotlib creates a Tk root object in the background to which the PhotoImage objects in images.py get assigned. This makes the images inaccessible by pandastable in the other Tk root object.

This answer on StackExchange suggests that adding master=something to the PhotoImage objects in images.py might help. However, I am not sure which would be a good master object and how to pass it into images.py.

here is the full stack trace:

  File "python3.7/site-packages/pandastable/core.py", line 306, in show
    self.statusbar = statusBar(self.parentframe, self)
  File "python3.7/site-packages/pandastable/core.py", line 3709, in __init__
    addButton(fr, 'Contract Cols', self.parentapp.contractColumns, img, 'contract columns', side=LEFT, padding=1)
  File "python3.7/site-packages/pandastable/dialogs.py", line 245, in addButton
    image=img, compound=compound, padding=padding)
  File "python3.7/tkinter/ttk.py", line 614, in __init__
    Widget.__init__(self, master, "ttk::button", kw)
  File "python3.7/tkinter/ttk.py", line 559, in __init__
    tkinter.Widget.__init__(self, master, widgetname, kw=kw)
  File "python3.7/tkinter/__init__.py", line 2299, in __init__
    (widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: image "pyimage10" doesn't exist

thawn avatar Jun 24 '20 21:06 thawn

I don't know how to solve that. but when you plot from pandastable it creates a PlotViewer object called pf that you can access and plot to. Maybe that's of use.

root = tkinter.Tk()
pane = tkinter.Canvas(root)
pdframe = pd.DataFrame()
table = Table(pane, dataframe=pdframe, showtoolbar=False, showstatusbar=True)
table.show()
table.plotSelected()
pf = table.pf
fig = pf.fig
ax = pf.ax
ax.plot(range(10),range(10))

pane.pack()
root.mainloop()

dmnfarrell avatar Jun 25 '20 10:06 dmnfarrell

@dmnfarrell Thanks a lot for the quick answer and the tip with table.pf object.

I think that the error I am getting may be related to the fact that the PhotoImage ojects are created without specifying a master tkinter object. This may cause them to be assigned to the wrong tkinter object (the one created by pyplot in my case), which in turn makes them unavailable for pandastable. Do you have an idea how to pass a tkinter object that belongs to pandastable to images.py? As far as I know, that tkinter object would not need to be the one where the images appear in the end, it just needs to be in the same tkinter object tree so that it can hold the images and keep them accessible to pandastable.

thawn avatar Jun 25 '20 17:06 thawn

Sorry I don't know how to do that. You'd have to ask someone who knows more about matplotlib. Maybe you could do it without using the pyplot interface. https://matplotlib.org/faq/usage_faq.html#matplotlib-pyplot-and-pylab-how-are-they-related

dmnfarrell avatar Jun 26 '20 10:06 dmnfarrell