python画图后程序会停止_使用Matplotlib,PyQt和Threading进行实时绘图会导致python崩溃...

1586010002-jmsa.png

I've been struggling with my Python application and I can't find any answers.

I'm having PyQT GUI application which uses Matplotlib widget. GUI starts a new thread which handles plotting to mpl widget. I'm afraid I run now to a race condition by accessing matplotlib drawing components from another thread which leads to crash.

This is basically, what my code looks like:

class Analyzer(QMainWindow, Ui_MainWindow):

def __init__(self, parent=None):

self.timer = QTimer()

super(Analyzer, self).__init__(parent)

self.setupUi(self)

self.background = self.mpl.canvas.copy_from_bbox(self.mpl.canvas.ax.bbox)

self.plotQueue = Queue.Queue()

self.plotterStarted = False

self.plotter = Plotter(self.mpl, self.plotQueue)

self.cam = Cam(self.plotQueue, self.textEdit)

...

class Ui_MainWindow(object):

def setupUi(self, MainWindow):

...

self.mpl = MplWidget(self.centralWidget)

...

class MplWidget(QtGui.QWidget):

"""Widget defined in Qt Designer"""

def __init__(self, parent = None):

QtGui.QWidget.__init__(self, parent)

self.canvas = MplCanvas()

...

class MplCanvas(FigureCanvas):

"""Class to represent the FigureCanvas widget"""

def __init__(self):

# setup Matplotlib Figure and Axis

self.fig = Figure()

self.ax = self.fig.add_subplot(111)

# initialization of the canvas

FigureCanvas.__init__(self, self.fig)

FigureCanvas.updateGeometry(self)

And plotter class:

class Plotter():

def __init__(self, mpl="", plotQueue=""):

self.mpl = mpl

self.background = self.mpl.canvas.copy_from_bbox(self.mpl.canvas.ax.bbox)

self.plotQueue = plotQueue

...

def start(self):

threading.Thread(target=self.run).start()

''' Real time plotting '''

def run(self):

while True:

try:

inputData = self.plotQueue.get(timeout=1)

# Go through samples

for samples in inputData:

self.line, = self.mpl.canvas.ax.plot(x, y, animated=True, label='Jee')

for sample in samples:

x.append(sample['tick'])

y.append(sample['linear'])

self.line.set_data(x,y)

self.mpl.canvas.ax.draw_artist(self.line)

self.mpl.canvas.blit(self.mpl.canvas.ax.bbox)

...

So I pass mpl and plotQueue to Plotter class object. PlotQueue is populated in Cam class which processes incoming data from external hw. Plotter reads the plotQueue, processes it and calls drawing for mpl.

But is this a thread safe method to access mpl? If not, how should I do it? Any tips on this are appreciated.

Edit 1.

I added QTimer in main thread to handle drawing, as suggested in comments. After a small tweaking, I got it working fairly well.

class Analyzer(...):

def __init__(self, parent=None):

QObject.connect(self.timer, SIGNAL("timeout()"), self.periodicCall)

def periodicCall(self):

self.plotter.draw()

def startButton(self):

self.timer.start(10)

Thanks a lot for useful comments.

解决方案

If matplotlib in your program is using the QT backend (which I assume it is since you are embedding it in a Qt application), then the drawing is going to be done in thread you call the matplotlib commands from. This is going to be a problem because Qt requires that all drawing is done from the main thread. So I'm fairly certain you can't fix it simply. (if you were using GTK you could use the gtk lock to prevent the main process from interacting with the GUI while you did GUI related things from your thread, but Qt got rid of their similar lock in v4 and above).

You have a few options:

Try and separate out the drawing parts of matplotlib (may not even be possible?) and have them run in the main thread by sending events with QApplication.postEvent()

Instead of using a thread, just use callbacks in the main thread (maybe called periodically using a QTimer or when the program is idle). This probbaly won't impact the performance of your application since the Python GIL prevents true multi-threading behaviour anyway.

Use a different plotting library. I had a look over PyQtGraph the other day, and it seems to be coming along nicely. From my brief glance I think it has the ability to handle all of this behind the scenes for you, using a RemoteGraphicsView. This would launch a second process for doing the CPU intensive plotting stuff, which gets around the aforementioned Python GIL issue. Check out the examples they provide if you are interested

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值