问题描述
在使用PyQt5为一个项目写UI界面的时候,我试图把matplotlib绘制的图像展示在UI界面的窗口中,但matplotlib是运行在一个子线程中的,这导致它出现了如下警告:UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fail.
并且我无法使用matplotlib.backends.backend_qt5agg
下的 FigureCanvasQTAgg
直接把图像绘制在UI窗口中,经过我测试如果matplotlib运行在主线程中的话就不会出现该问题。
解决方法
我用了一个笨办法,那就是使用IO.BytesIO()
把matplotlib绘制的图像以png或者jpeg格式的二进制流保存在内存中,然后用PIL.Image.open()
打开为图片,然后把这张图片经过处理后传递给窗口显示。
buf = io.BytesIO()
fig.savefig(buf, format="png", dpi=100)
buf.seek(0)
img = Image.open(buf)
下面说说图片处理过程:我使用的是QLabel来展示图片,这就需要图片数据类型类型是PyQt5.QtGui.QImage
。经常使用下面的代码来展示:
image = QImage(img.data, img.shape[1], img.shape[0], QImage.Format_RGB888)
label.setPixmap(QPixmap.fromImage(image))
其中的img必须是numpy.ndarray
类型的,但目前我们获得的img是PIL.PngImagePlugin.PngImageFile
类型的。我们可以使用img = numpy.asarray(img)
来进行转换,这样就可以使用上面的代码进行展示了。
img = Image.open(buf)
img = np.asarray(img)
image = QImage(img.data, img.shape[1], img.shape[0], QImage.Format_RGB888)
label.setPixmap(QPixmap.fromImage(image))
奇怪的是不知道为什么,通过这样的方法展示出来的图片却总是损坏的,如下图。
通过打印查看转换为numpy.ndarray类型后的图片数组发现里面大部分数据都是255,但是将这张图片再转换回PIL类型的数据展示或者使用opencv显示却都没问题,这一度让我束手无策。
直到我发现PIL.PngImagePlugin.PngImageFile
类型的图片可以使用PIL.ImageQt
直接转换为QImage类型进行展示,通过如下代码:文章来源:https://www.toymoban.com/news/detail-478712.html
image = ImageQt.ImageQt(img1)
label.setPixmap(QPixmap.fromImage(image))
ok,到这里我的问题就解决啦!最终在UI界面得到了如下效果。
文章来源地址https://www.toymoban.com/news/detail-478712.html
到了这里,关于【pyqt5】【多线程】【matplotlib】解决子线程上运行的matplotlib无法在主线程上的UI界面上绘制图形的问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!