2013-10-29 92 views
9

我知道在matplotlib和線程上有相當多的問題,而且pyplot也不是線程。但是,我無法找到關於這個特定問題的任何信息。我想要做的是:繪製一個數字並每秒更新一次。爲此,我想創建一個線程,但到目前爲止,我甚至無法從線程中獲得真實的情節。另外,我堅持使用qt4,所以它可能是其他後端行爲不同。在線程中使用matplotlib繪圖

下面是一個非常簡單的例子:在plot_a_graph()中創建了一個圖表。當從主程序調用時,這工作正常,但延遲了主代碼的進一步執行。但是,從線程調用時,不會顯示圖形。

import matplotlib 
matplotlib.use("qt4agg") 
import matplotlib.pyplot as plt 
import threading 
import time 

def plot_a_graph(): 
    f,a = plt.subplots(1) 
    line = plt.plot(range(10)) 
    plt.show() 
    print "plotted graph"  
    time.sleep(4) 


testthread = threading.Thread(target=plot_a_graph) 

plot_a_graph()  # this works fine, displays the graph and waits 
print "that took some time" 

testthread.start() # Thread starts, window is opened but no graph appears 
print "already there" 

THX您的幫助

+1

貴公司的所有繪圖的主線程上。至少在QT中,如果您嘗試這樣做,gui不會喜歡它。 – tacaswell

回答

8

我的建議在這裏使用Python multiprocessing模塊,而不是線程模塊。我已經能夠對你的示例代碼只做一些細微的修改,並且在主進程中的控制流程繼續時(見下面的代碼),成功地將matplotlib繪圖卸載到子進程。

如果您希望子進程在較大的代碼控制流的上下文中與父進程進行通信,我建議閱讀多處理文檔或任何有關此主題的大量博客文章(在你的問題中沒有完全描述)。請注意,多處理還有一個優點,即可以繞過python global interpreter lock &,從而允許您利用多核計算機體系結構。

#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

thx!不幸的是,我曾嘗試過,我得到的是一個錯誤: ... PicklingError:不能pickle :找不到__main __。plot_a_graph – Fabian

0

使用Qt的信號打電話給你的繪圖功能在主線程

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()