2013-10-01 15 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