使用颜色条删除图像不会释放 matplotlib 中的内存?

Posted

技术标签:

【中文标题】使用颜色条删除图像不会释放 matplotlib 中的内存?【英文标题】:remove image with colorbar won't release the memory in matplotlib? 【发布时间】:2022-01-24 04:01:43 【问题描述】:

我正在尝试从图形中删除图像并释放内存。图片不加colorbar时,可以成功释放内存,如果加colorbar则失败。在下面的演示代码中:

    单击按钮添加颜色条将为图中的一个图像添加一个颜色条。 单击按钮删除将从图中删除一个图像(和相关的颜色条)。

每次删除图片,相关的colorbar也被删除了,所以不知道为什么内存回收失败,我猜想添加colorbar的时候一定是对图片有一些额外的引用,失败了内存回收。

import numpy as np
from PyQt5 import QtWidgets
from memory_profiler import profile
import matplotlib
from matplotlib.figure import Figure
import matplotlib.cm as cm
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.axes._axes import Axes

matplotlib.use("Qt5Agg")


class MplCanvas(FigureCanvasQTAgg):
    def __init__(self, parent=None, width=5, height=4, dpi=100):
        self.fig = Figure(figsize=(width, height), dpi=dpi)
        self.axe = self.fig.add_subplot(1, 1, 1, label='good')
        super().__init__(self.fig)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        layout = QtWidgets.QVBoxLayout()

        self.canvas = MplCanvas(self, width=5, height=4, dpi=100)
        self.axe = self.canvas.axe

        layout.addWidget(self.canvas)

        self.pushButton_addColorBar = QtWidgets.QPushButton('Add ColorBar')
        layout.addWidget(self.pushButton_addColorBar)
        self.pushButton_remove = QtWidgets.QPushButton('remove')
        layout.addWidget(self.pushButton_remove)

        widget = QtWidgets.QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)

        self.pushButton_remove.clicked.connect(self.removeImage)
        self.pushButton_addColorBar.clicked.connect(self.createColorBar)

        self.pcolormesh_test()

    def pcolormesh_test(self):
        """add two images"""
        delta = 0.01
        x = y = np.arange(-3.0, 3.0, delta)
        X, Y = np.meshgrid(x, y)
        Z1 = np.exp(-X ** 2 - Y ** 2)
        Z2 = np.exp(-(X - 1) ** 2 - (Y - 1) ** 2)
        Z = (Z1 - Z2) * 2

        im = self.axe.pcolormesh(X, Y, Z, cmap=cm.viridis, shading='auto')
        im.set_clim(vmax=np.amax(Z), vmin=np.amin(Z))

        Zx = (Z1 + Z2) * 2
        imx = self.axe.pcolormesh(X, Y, Zx, cmap=cm.Blues, shading='auto')
        imx.set_clim(vmax=np.amax(Zx), vmin=np.amin(Zx))

    def createColorBar(self):
        """ to create a color bar for an image. """
        axe = self.axe
        fig = axe.get_figure()
        images = self.getImages(axe)

        for image in images:
            if not image.colorbar:  # color bar doesn't exist
                inset_axe = axe.inset_axes([1.0, 0, 0.05, 1], transform=axe.transAxes)
                fig.colorbar(image, ax=axe, cax=inset_axe)
                break  # each trigger create one colorbar for one image

        self.reDraw()

    @profile
    def removeImage(self, checked):
        """
        Usage:
            * each trigger remove one image

        """
        images = self.getImages(self.axe)
        # print(f'images=images')

        if images:
            image = images[-1]
            color_bar = image.colorbar
            if color_bar:
                color_bar.remove()
                del color_bar

            # remove image
            image.remove()
            del image

        self.reDraw()

    def getImages(self, axe: Axes):
        """to obtain the image list in the axe"""
        images = []
        images.extend(axe.images)
        images.extend(axe.collections)

        return images

    def reDraw(self):
        self.canvas.draw_idle()
        self.canvas.flush_events()


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)

    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

【问题讨论】:

【参考方案1】:

我已经找到解决方案,并发布答案以寻求帮助。

我们需要在removeImage()方法的末尾添加gc.collect()。那么当图像被删除时,内存可以被回收。

【讨论】:

以上是关于使用颜色条删除图像不会释放 matplotlib 中的内存?的主要内容,如果未能解决你的问题,请参考以下文章

matplotlib 中的科学记数法颜色条

从 matplotlib 中的图形中删除颜色条

Matplotlib - 如何删除颜色条但保持热图位置不变

删除颜色条的边框 matplotlib

Matplotlib - 如何使用对数刻度设置线图的颜色条

在 matplotlib 中创建一个离散的颜色条