2

I want to display a matplotlib figure in a python application with a tkinter GUI. To avoid blocking UI-features while the figure is being created and drawn to the UI, this has to be done in another thread. How do I draw the plot in a different thread than the one containing the tkinter root and frame?

I have tried using the threading module, and managed to create a figure in another thread. However when I try to create a canvas with the figure the application crashes and outputs 'WARNING: QApplication was not created in the main() thread.'

Imports

from tkinter import *
from tkinter import ttk

import matplotlib
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

from threading import Thread

Everything is in the same class right now. I create the root, mainframe and a button in the constructor

def __init__(self):
    # Creates root and mainframe
    self.root = Tk()
    self.mainframe = ttk.Frame(self.root, padding="3 3 12 12")
    self.mainframe.grid(column=0, row=0, sticky=(N, W, E, S))

    # Creates button that runs 'handle_input_change'-method on click
    ttk.Button(self.mainframe, text="Show graph", 
    command=self.handle_input_change).grid(column=3, row=4, sticky=E)

The method that runs when the button is clicked

def handle_input_change(self, *args):
    # Starts another thread running the 'plot_current_data'-method
    thread = Thread(target = self.plot_current_data)
    thread.start()
def plot_current_data(self):
    fig = # ... (irrelevant, could be any matplotlib figure)

    # This is what makes the application crash and output the warning message
    canvas = FigureCanvasTkAgg(fig, master=self.mainframe)
    canvas.draw()
    canvas.get_tk_widget().grid(column=1, row=5, rowspan=10, sticky=W)

When i run it all in the same thread, the code above does display the figure.

Adis
  • 21
  • 1
  • 3
  • You cannot put a GUI in any other thread than the main thread. This means you also cannot draw a matplotlib plot in any other thread. – ImportanceOfBeingErnest Oct 11 '19 at 13:36
  • All the GUI related operation have to occurs in the GUI thread. So you need to somehow hand over your fig to the GUI thread. Here is an example of queues used to communicate between threads: https://stackoverflow.com/a/1198288/ – FabienAndre Oct 11 '19 at 14:42

1 Answers1

0

Worked for me by creating the canvas on the main thread first. Then can call canvas_tkagg.draw() on another thread. Python 3.11.1 / Windows10

craigB
  • 372
  • 1
  • 3
  • 13