2013-10-01 14 views
4

一直在玩Python的繪圖庫,並遇到了matplotlib,似乎已經進行了戰鬥測試和驗證。然而,我在線程中創建一個簡單的情節時遇到了一個問題。matplotlib繪製在簡單的線程中凍結

在本例中波紋管,虛擬plotme方法是在一個線程連續運行兩次,但它可以在第二次迭代卡/凍結。 最有可能是明顯的,並與線程本身有關,但我沒有發現它迄今。

import matplotlib.pyplot as plt 
from numpy import arange, sin, pi 
import threading 

class Dummy(): 

    def plotme(self, iteration = 1): 

     print "%ix plotting... " % iteration, 
     t = arange(0.0, 2.0, 0.01) 
     s = sin(2*pi*t) 
     plt.plot(t, s) 
     plt.xlabel('time (s)') 
     plt.ylabel('voltage (mV)') 
     plt.title('About as simple as it gets, folks') 
     #savefig("test.png") # irrelevant here 
     plt.close() 

    def threadme(self, iteration = 1): 

     thread_plot = threading.Thread(target=self.plotme, 
             args=(iteration,)) 
     thread_plot.start() 
     thread_plot.join() 

dummy = Dummy() 
dummy.threadme(1) 
dummy.threadme(2) 
+1

您是否知道在matplotlib.pyplot的命令不是安全的?您應該使用OOÜP方法,例如創建一個圖形,一個軸對象,然後調用該軸對象上的方法,例如, 'ax.plot(...)' –

回答

5

首先,請注意,pyplot -interface不是線程安全的。

然後:使用「Agg」 - 後端進行非交互式創建多個圖像。

工作示例(與由於螺紋可能出現的問題)是:

import matplotlib 
matplotlib.use("Agg") 
import matplotlib.pyplot as plt 
from numpy import arange, sin, pi 
import threading 

class Dummy(): 

    def plotme(self, iteration = 1): 

     print "%ix plotting... " % iteration, 
     t = arange(0.0, 2.0, 0.01) 
     s = sin(2*pi*t) 
     plt.plot(t, s) 
     plt.xlabel('time (s)') 
     plt.ylabel('voltage (mV)') 
     plt.title('About as simple as it gets, folks') 
     plt.savefig("19110942_%i_test.png" % iteration) # irrelevant here 
     plt.clf() 

    def threadme(self, iteration = 1): 

     thread_plot = threading.Thread(target=self.plotme, 
             args=(iteration,)) 
     thread_plot.start() 
     thread_plot.join() 

dummy = Dummy() 
dummy.threadme(1) 
dummy.threadme(2) 

一個線程安全的版本是這樣的:

import matplotlib 
matplotlib.use("Agg") 
import matplotlib.pyplot as plt 
from numpy import arange, sin, pi 
import threading 

class Dummy(): 

    def plotme(self, iteration = 1): 

     print "%ix plotting... " % iteration, 
     t = arange(0.0, 2.0, 0.01) 
     s = sin(2*pi*t) 

     fig, ax = plt.subplots() 
     ax.plot(t, s) 
     ax.set_xlabel('time (s)') 
     ax.set_ylabel('voltage (mV)') 
     ax.set_title('About as simple as it gets, folks (%i)' % iteration) 
     fig.savefig("19110942_%i_test.png" % iteration) 

    def threadme(self, iteration = 1): 

     thread_plot = threading.Thread(target=self.plotme, 
             args=(iteration,)) 
     thread_plot.start() 
     thread_plot.join() 

dummy = Dummy() 
dummy.threadme(1) 
dummy.threadme(2) 
+0

謝謝@Thorsten Kranz就是這樣。我應該仔細研究pyplot的「線程安全性」:) –

+1

注意:在過去的幾天裏我一直在玩這個遊戲,並且可以有把握地說,上面的第二個版本不是比'線程安全'更第一個,如果沒有調用'matplotlib.use('Agg')',兩者都會高興地掛在隨後的線程運行上**。關鍵是使用非交互模式,然後兩個人都會很高興地在線程中多次運行而不會出錯。 – SiHa

+2

**交互**繪圖的任何線程安全選項? – SPRajagopal