PyQt5 中嵌入Matplotlib图像

本文描述了解决了一个项目中PyQt5应用中实时显示热力图导致内存占用过高的问题,通过优化代码,将控件创建移到初始化过程,解决了内存泄漏,并分享了相关代码示例和解决步骤。

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

此问题源于某项目中一部分功能需要实时(为呈现良好的视觉效果,实际上是间隔几秒刷新)显示各变量之间的相关性。前期偷懒直接使用从服务器获取的相关度数据绘制相关性热度图并保存为本地图像文件,之后在PyQt界面中加载图像并显示。一番操作之后,虽然实现了实时刷新显示的功能,但在软件实际使用过程中出现软件内存占用率随运行时间增加,直至最后卡死的现象。初步分析可能是显示图像时每刷新一次就加载一幅图像,从而导致的内存占用越来越大,查了PyQt5中与QPixmap相关的方法依然没有解决,最终下定决心重写这部分功能的相关代码,但即便使用实时绘图的方式依然没有解决内存占用逐步增加的问题,最终发现解决这一问题的关键步骤是将控件的创建等相关代码放到初始化过程中。修改完成后,软件运行时内存占用稳定,特此记录此次代码修改,主要解决以下三个问题:

(1) 定时刷新图像

使用从服务器获取的数据在画布上进行绘图,数据更新则画布同步更新,此代码段中没有实现更新数据相关代码

(2) 调整颜色条位置

使用add_axes()添加绘图区域,绘制颜色条可精细调控其位置

(3) 解决内存占用逐步增加的问题

将控件创建等相关代码放到初始化过程中,使图像显示控件只初始化一次

代码示例效果

点击更新图像按钮,可刷新显示图片(代码示例中没有更新数据,所以图片是一样的)

功能简化后的代码如下:

"""
数据定时更新的情况下,绘制热度图。使用按钮模拟数据更新
"""
import sys
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QHBoxLayout, QWidget


class MyApp(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(1400, 1400)
        self.setWindowTitle('PyQt5 更新绘制图像')

        # 创建一个按钮,点击时更新图像
        self.button = QtWidgets.QPushButton(self)
        self.button.setText('更新图像')
        self.button.clicked.connect(self.update_image)

        # 创建一个垂直布局,将 QLabel 和按钮添加到布局中
        self.layout1 = QVBoxLayout()
        self.layout1.addWidget(self.button)
        self.heatmap_fig = plt.figure(figsize=(6, 4), dpi=300)
        self.layout2 = QHBoxLayout()

        self.layout = QVBoxLayout(self)  # 至少主布局要在UI界面上,最好每个子布局也在,因此继承自self
        self.layout.addStretch()
        self.layout.addLayout(self.layout1)
        self.layout.addStretch()
        self.layout.addLayout(self.layout2)
        self.layout.setStretch(0, 1)
        self.layout.setStretch(1, 2)
        self.layout.setStretch(2, 1)
        self.layout.setStretch(3, 20)

        self.canvas = FigureCanvas(self.heatmap_fig)
        self.layout2.addWidget(self.canvas)

    def update_image(self):
        # plt.cla()  # 清除axes
        plt.clf()  # 每次调用绘图函数时先清空上一次的画布figure
        # 随机生成一个新的图像
        self.data = np.array([[0, 0.8, 0.5, 0.7, 0.2, 0.6, 0.3, 0.4, 0.6]])
        xstick = ['sirox出口物料温度', '烘梗丝(滚筒)-热风温度', '烘梗丝(滚筒)-热风风速',
                  '烘梗丝(滚筒)-热风开度',
                  '烘梗丝(滚筒)-出料罩压力',
                  '烘梗丝(滚筒)-筒壁温度', '烘梗丝(滚筒)-排潮开度', '烘梗丝(滚筒)-出口物料温度',
                  '入口物料含水率']
        ystick = ['相关度']

        colormap = plt.cm.jet
        plt.rcParams['font.sans-serif'] = ['SimHei']
        # self.heatmap_fig = plt.figure(figsize=(6, 4), dpi=400)

        plt.title('相关度分析热度图', y=-1, size=15, color='white')
        ax = sns.heatmap(self.data.astype(float), linewidths=0.1, vmax=1.0, vmin=0, square=True, cmap=colormap,
                         linecolor='#274E91', annot=True, cbar=False)

        # 设置画布背景颜色
        self.heatmap_fig.patch.set_facecolor('#274E91')

        ### 设置x轴位置,原来x轴在中间,现将x轴望下移,靠经底部
        heatmap_Box = ax.get_position()
        # print(heatmap_Box.x0,heatmap_Box.y0,heatmap_Box.width,heatmap_Box.height)

        ax.set_position([0.14, 0.008, 0.8, 0.8])

        ### heatmap 自带的颜色条不能精细调整位置,故重新绘制颜色条
        ### 关闭 cb.ax.set_xticklabels的警告信息
        import warnings

        warnings.filterwarnings("ignore")

        position = ax.figure.add_axes([0.12, 0.08, 0.78, 0.085], )  # 设置颜色条位置[左,下,右,上]
        cb = ax.figure.colorbar(ax.collections[0], cax=position, orientation='horizontal')  # 显示colorbar
        cb.ax.tick_params(labelsize=15, color='white')  # 设置colorbar刻度字体大小颜色
        cb.ax.set_xticklabels(labels=[0.0, 0.2, 0.4, 0.6, 0.8, 1.0], color='white', rotation=0)  # 设置colorbar标签名称

        # 控制标签上下左右,坐标轴刻度的颜色
        ax.tick_params(color='white', right=False, top=True, labelright=False, labeltop=True, left=True, bottom=False,
                       labelleft=True, labelsize=11, labelbottom=False)
        # 控制刻度名称的颜色
        ax.set_xticklabels(xstick, color='white', rotation=80)
        ax.set_yticklabels(ystick, color='white', rotation=0)

        self.canvas.draw()  # 绘制图像并显示
        plt.savefig('tmp.jpg')


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MyApp()
    window.show()
    sys.exit(app.exec_())

参考

记录一次PyQt5内存泄漏的问题解决

Python可视化matplotlib&seborn14-热图heatmap

python使用seaborn画热力图中设置colorbar图例刻度字体大小

matplotlib:先搞明白plt. /ax./ fig再画

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值