1

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

Community
  • 1
  • 1
Dzhao
  • 683
  • 1
  • 9
  • 22
  • 1
    You may need to change the backend for matplotlib, i.e. `import matplotlib` followed by `matplotlib.use('Agg')` – J.J. Hakala Apr 16 '16 at 04:15
  • @J.J.Hakala Thanks for the tip I'm looking into it. But... Could you explain to me what the general meaning of 'back end' means? What is the big picture? – Dzhao Apr 17 '16 at 03:49

0 Answers0