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

在使用PyQT GUI和Matplotlib进行实时绘图时,程序可能会因多线程访问导致崩溃。解决方案包括通过QTimer在主线程中处理绘图,或者考虑使用其他支持后台绘制的库如PyQtGraph。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值