【pyqt5】【多线程】【matplotlib】解决子线程上运行的matplotlib无法在主线程上的UI界面上绘制图形的问题

问题描述

在使用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类型进行展示,通过如下代码:

image = ImageQt.ImageQt(img1)
label.setPixmap(QPixmap.fromImage(image))

ok,到这里我的问题就解决啦!最终在UI界面得到了如下效果。
在这里插入图片描述

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
要在PyQt5设计的GUI界面中显示读取文件matplotlib绘制图形,可以采用以下步骤: 1. 导入必要的库 ``` import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure ``` 2. 创建一个绘图函数,以便将读取的数据绘制图形 ``` def plot_data(data): fig = Figure(figsize=(5, 4), dpi=100) ax = fig.add_subplot(111) ax.plot(data) return fig ``` 3. 在窗口中创建一个QWidget,将绘图控件添加到其中,并设置布局 ``` class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle('My Application') self.setGeometry(100, 100, 800, 600) central_widget = QWidget(self) self.setCentralWidget(central_widget) layout = QVBoxLayout(central_widget) canvas = FigureCanvas(plot_data(data)) layout.addWidget(canvas) ``` 4. 运行程序,即可在GUI界面中显示读取文件matplotlib绘制图形。 完整代码如下: ``` import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure def plot_data(data): fig = Figure(figsize=(5, 4), dpi=100) ax = fig.add_subplot(111) ax.plot(data) return fig class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle('My Application') self.setGeometry(100, 100, 800, 600) central_widget = QWidget(self) self.setCentralWidget(central_widget) layout = QVBoxLayout(central_widget) canvas = FigureCanvas(plot_data(data)) layout.addWidget(canvas) if __name__ == '__main__': app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_()) ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值