TLDR: I can't save my graphs from matplotlib
without my tkinter
GUI acting up even though my GUI is running in the main thread and the matplotlib
functions are called within a separate thread.
I am trying to make graphs in python. I am using matplotlib
. I have successfully plotted my first graph however, the problem I'm facing seems to be related my GUI that is written in tkinter
. I am using Python3.
In short, my code reads binary files and makes a graph for each binary file. So in my function read_files
, which when run is its own thread, I have a for loop of reading the binary file and creating a plot and saving the plot.
Upon running my script, I receive this error:
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Python34\lib\threading.py", line 911, in _bootstrap_inner
self.run()
File "C:\Python34\lib\threading.py", line 859, in run
self._target(*self._args, **self._kwargs)
File "C:\Python34\Projects\PurgePressureAnalysis\GUI.py", line 77, in callback
self.function_chain_v1()
File "C:\Python34\Projects\PurgePressureAnalysis\GUI.py", line 101, in function_chain_v1
(func.__func__)(self.infoObj)
File "C:\Python34\Projects\PurgePressureAnalysis\lib\features.py", line 96, in waveform_analysis
Graph.plot_lt_wvfrm(case_wvfrm)
File "C:\Python34\Projects\PurgePressureAnalysis\lib\graph.py", line 18, in plot_lt_wvfrm
fig = plt.figure()
File "C:\Python34\lib\site-packages\matplotlib\pyplot.py", line 527, in figure
**kwargs)
File "C:\Python34\lib\site-packages\matplotlib\backends\backend_tkagg.py", line 84, in new_figure_manager
return new_figure_manager_given_figure(num, figure)
File "C:\Python34\lib\site-packages\matplotlib\backends\backend_tkagg.py", line 101, in new_figure_manager_given_figure
icon_img = Tk.PhotoImage(file=icon_fname)
File "C:\Python34\lib\tkinter\__init__.py", line 3421, in __init__
Image.__init__(self, 'photo', name, cnf, master, **kw)
File "C:\Python34\lib\tkinter\__init__.py", line 3377, in __init__
self.tk.call(('image', 'create', imgtype, name,) + options)
RuntimeError: main thread is not in main loop
After reading this question, I know that the problem is related to tkinter
and not matplotlib
. I have confirmed this because I successfully saved my plot before the error was thrown.
Here are the relevant parts of my code (some parts are cut out for simplification):
This is the function called when I click on a button in my GUI.
def Search(self):
def callback():
try:
self.function_chain_v1()
self.add_text('Search Complete')
except OSError as e:
handle_exceptions()
self.t = threading.Thread(target = callback)
self.t.start()
This function calls my plot and save function. This function is called in Thread-1. (some parts have been cut out for simplicity):
@staticmethod
def waveform_analysis(infoObj):
for case in infoObj.filelist:
wvfrm_per_case = []
case_wvfrm = []
for index in range(len(case)):
case_wvfrm = read_binary() #simplification of what is really happening
Convert.convert_wvfrm_to_csv(case_wvfrm, a)
Graph.plot_lt_wvfrm(case_wvfrm)
return infoObj.output
And this is the plot function This function is called in Thread-1.:
@staticmethod
def plot_lt_wvfrm(wvfrms):
fig = plt.figure()
ax1 = plt.subplot2grid((2,1), (0,0), rowspan = 1)
ax2 = plt.subplot2grid((2,1), (1,0), rowspan = 1)
x, y = read(channel_y, purge_y, wvfrms)
for ys in y:
ax1.plot(x, ys)
x, y = read(purge_y, len(wvfrms[0]), wvfrms)
for ys in y:
ax2.plot(x, ys)
plt.savefig('C:\\Users\\dzhao\\Desktop\\' + str(wvfrms[0][1]) + '.png')
What I've tried:
I've tried putting this Graph.plot_lt_wvfrm
into another thread (so a thread within a thread) and the .png file was successfully saved but this error related to tkinter
still occurs. I've looked into Queues from this question but I'm hesitant to try this because I'm not sure if queues will solve the root cause of this error. I've also tried moving some of the functions related to matplotlib
into the main thread (like `fig = plt.figure()) but this didn't do anything.
All I know is that this is a thread related issue because matplotlib
also uses tkinter
and somewhere they're fighting over something.
Yeah... you can tell my understanding of this problem by how vague my analysis is.
How do I keep my GUI working (preventing this RunTimeError
from appearing) but also have my graph making + saving function work?
Other questions I've looked at: context context2 context3 context 4