Plotting with matplotlib in threads

前端 未结 2 1156
忘掉有多难
忘掉有多难 2020-12-16 15:30

I know there are quite some questions on matplotlib and threading, also that pyplot is not threadsave. I couldn\'t find anything on this particular problem however. What I w

相关标签:
2条回答
  • 2020-12-16 16:08

    My suggestion here is to use the python multiprocessing module instead of the threading module. I've been able to perform only slight modifications to your sample code and successfully offload the matplotlib plotting to a child process while the control flow in the main process continues (see code below).

    I do suggest reading the multiprocessing documentation, or any of the plethora of blog posts on the subject, if you want the child process(es) to communicate back & forth with the parent in the context of your larger code control flow (which isn't fully described in your question). Note that multiprocessing has the added advantage of circumventing the python global interpreter lock & allowing you to exploit multi-core computer architectures.

    #a slight modification of your code using multiprocessing
    import matplotlib
    matplotlib.use("qt4agg")
    import matplotlib.pyplot as plt 
    #import threading
    #let's try using multiprocessing instead of threading module:
    import multiprocessing
    import time
    
    #we'll keep the same plotting function, except for one change--I'm going to use the multiprocessing module to report the plotting of the graph from the child process (on another core):
    def plot_a_graph():
        f,a = plt.subplots(1)
        line = plt.plot(range(10))
        print multiprocessing.current_process().name,"starting plot show process" #print statement preceded by true process name
        plt.show() #I think the code in the child will stop here until the graph is closed
        print multiprocessing.current_process().name,"plotted graph" #print statement preceded by true process name
        time.sleep(4)
    
    #use the multiprocessing module to perform the plotting activity in another process (i.e., on another core):
    job_for_another_core = multiprocessing.Process(target=plot_a_graph,args=())
    job_for_another_core.start()
    
    #the follow print statement will also be modified to demonstrate that it comes from the parent process, and should happen without substantial delay as another process performs the plotting operation:
    print multiprocessing.current_process().name, "The main process is continuing while another process deals with plotting."
    
    0 讨论(0)
  • 2020-12-16 16:16

    Use a Qt signal to call your plotting function in the main thread

    import matplotlib
    matplotlib.use("qt4agg")
    import matplotlib.pyplot as plt
    import threading
    import time
    
    from PyQt4 import QtCore
    
    class Call_in_QT_main_loop(QtCore.QObject):
        signal = QtCore.pyqtSignal()
    
        def __init__(self, func):
            super().__init__()
            self.func = func
            self.args = list()
            self.kwargs = dict()
            self.signal.connect(self._target)
    
        def _target(self):
            self.func(*self.args, **self.kwargs)
    
        def __call__(self, *args, **kwargs):
            self.args = args
            self.kwargs = kwargs
            self.signal.emit()
    
    @Call_in_QT_main_loop
    def plot_a_graph():
        f,a = plt.subplots(1)
        line = plt.plot(range(10))
        plt.show()
        print("plotted graph")
        print(threading.current_thread())  # print the thread that runs this code
    
    def worker():
        plot_a_graph()
        print(threading.current_thread())  # print the thread that runs this code
        time.sleep(4)
    
    testthread = threading.Thread(target=worker)
    
    testthread.start()
    
    0 讨论(0)
提交回复
热议问题