memory leak with PyQt4 plus savefig or print_figure

Hi,

I am working on a PyQt4 application with some embedded MPL figures, and am also trying to save some figures as png’s without displaying them. I am observing huge memory increases (10s or 100s of Mb) the moment I try to save a png. I reproduced the issue by combining two mpl examples, http://matplotlib.sourceforge.net/examples/user_interfaces/embedding_in_qt4.html and http://matplotlib.sourceforge.net/examples/api/agg_oo.html. Full code is attached. When pressing the “save figure” button, memory usage shoots up, multiple clicks keep sending it higher (although not monotonically).

I tested on two different platforms

  • Matplotlib 98.5.2 and Python 2.6.2 on Ubuntu.
  • latest Enthought Python Distribution on Windows XP.

The function that does the png saving is:

def save_png():

"""Save an image as a png file"""

pngpath = 'test_mplsave.png'

fig = Figure()
canvas = FigureCanvas(fig)
ax = fig.add_subplot(111)
x = arange(5e3)

ax.plot(x, sin(x))
canvas.print_figure(pngpath)

## tried all things commented out below, all makes no difference ##
#fig.savefig(pngpath)

#del(fig)
#del(canvas)
#del(ax)

#import matplotlib.pyplot as plt
#plt.close(fig)

#import gc
#gc.collect()

Commenting out the canvas.print_figure line fixes the issue.

Am I doing something obviously wrong, or mixing two incompatible ways of doing things?

Cheers,
Ralf

mpl_qt4gui.py (3.15 KB)

It is not surprising that memory usage is much lower without printing the plot. Very little is actually done by the "plot" command other than setting up a tree of objects that is later rendered during the printing process (where most of the work happens).

The attached script based on what you provided doesn't leak memory for me with matplotlib 0.98.5.2. It would appear that there is something else in your application triggering the leak. Perhaps there is something holding a reference longer than it should?

You can see from the attached massif plots that memory usage never becomes unbounded. It is normal for Python to delay deallocation for efficiency reasons. Calling gc.collect (the second graph) does help keep memory usage more compact however, if that is a primary concern.

Cheers,
Mike

Ralf Gommers wrote:

memleak2.py (559 Bytes)

massif.19516.ps (93.7 KB)

massif.19607.ps (96.8 KB)

···

Hi,

I am working on a PyQt4 application with some embedded MPL figures, and am also trying to save some figures as png's without displaying them. I am observing huge memory increases (10s or 100s of Mb) the moment I try to save a png. I reproduced the issue by combining two mpl examples, http://matplotlib.sourceforge.net/examples/user_interfaces/embedding_in_qt4.html and http://matplotlib.sourceforge.net/examples/api/agg_oo.html. Full code is attached. When pressing the "save figure" button, memory usage shoots up, multiple clicks keep sending it higher (although not monotonically).

I tested on two different platforms
- Matplotlib 98.5.2 and Python 2.6.2 on Ubuntu.
- latest Enthought Python Distribution on Windows XP.

The function that does the png saving is:

def save_png():
    """Save an image as a png file"""

    pngpath = 'test_mplsave.png'

    fig = Figure()
    canvas = FigureCanvas(fig)
    ax = fig.add_subplot(111)
    x = arange(5e3)
    ax.plot(x, sin(x))
    canvas.print_figure(pngpath)

    ## tried all things commented out below, all makes no difference ##
    #fig.savefig(pngpath)

    #del(fig)
    #del(canvas)
    #del(ax)

    #import matplotlib.pyplot as plt
    #plt.close(fig)

    #import gc
    #gc.collect()

Commenting out the canvas.print_figure line fixes the issue.

Am I doing something obviously wrong, or mixing two incompatible ways of doing things?

Cheers,
Ralf

------------------------------------------------------------------------

------------------------------------------------------------------------------
------------------------------------------------------------------------

_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

--
Michael Droettboom
Science Software Branch
Operations and Engineering Division
Space Telescope Science Institute
Operated by AURA for NASA

Ralph,

Perhaps time to migrate to Chaco API from Enthought? not sure if there is
Ubuntu support yet however.

Alex Baker

http://code.enthought.com/chaco/

Ralf Gommers-2 wrote:

···

Hi,

I am working on a PyQt4 application with some embedded MPL figures, and am
also trying to save some figures as png's without displaying them. I am
observing huge memory increases (10s or 100s of Mb) the moment I try to
save
a png. I reproduced the issue by combining two mpl examples,
http://matplotlib.sourceforge.net/examples/user_interfaces/embedding_in_qt4.htmland
http://matplotlib.sourceforge.net/examples/api/agg_oo.html. Full code is
attached. When pressing the "save figure" button, memory usage shoots up,
multiple clicks keep sending it higher (although not monotonically).

I tested on two different platforms
- Matplotlib 98.5.2 and Python 2.6.2 on Ubuntu.
- latest Enthought Python Distribution on Windows XP.

The function that does the png saving is:

def save_png():
    """Save an image as a png file"""

    pngpath = 'test_mplsave.png'

    fig = Figure()
    canvas = FigureCanvas(fig)
    ax = fig.add_subplot(111)
    x = arange(5e3)
    ax.plot(x, sin(x))
    canvas.print_figure(pngpath)

    ## tried all things commented out below, all makes no difference ##
    #fig.savefig(pngpath)

    #del(fig)
    #del(canvas)
    #del(ax)

    #import matplotlib.pyplot as plt
    #plt.close(fig)

    #import gc
    #gc.collect()

Commenting out the canvas.print_figure line fixes the issue.

Am I doing something obviously wrong, or mixing two incompatible ways of
doing things?

Cheers,
Ralf

#!/usr/bin/env python

# embedding_in_qt4.py --- Simple Qt4 application embedding matplotlib
canvases
#
# Copyright (C) 2005 Florent Rougon
# 2006 Darren Dale
#
# This file is an example program for matplotlib. It may be used and
# modified with no restriction; raw copies as well as modified versions
# may be distributed without limitation.

import sys, os, random
from PyQt4 import QtGui, QtCore

from numpy import arange, sin, pi
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as
FigureCanvas
from matplotlib.figure import Figure

class MyMplCanvas(FigureCanvas):
    """Ultimately, this is a QWidget (as well as a FigureCanvasAgg,
etc.)."""
    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = fig.add_subplot(111)
        # We want the axes cleared every time plot() is called
        self.axes.hold(False)

        self.compute_initial_figure()

        FigureCanvas.__init__(self, fig)
        self.setParent(parent)

        FigureCanvas.setSizePolicy(self,
                                   QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

    def compute_initial_figure(self):
        pass

class MyStaticMplCanvas(MyMplCanvas):
    """Simple canvas with a sine plot."""
    def compute_initial_figure(self):
        t = arange(0.0, 3.0, 0.01)
        s = sin(2*pi*t)
        self.axes.plot(t, s)

def save_png():
    """Save an image as a png file"""

    pngpath = 'test_mplsave.png'

    fig = Figure()
    canvas = FigureCanvas(fig)
    ax = fig.add_subplot(111)
    x = arange(5e3)
    ax.plot(x, sin(x))
    #canvas.print_figure(pngpath)

    ## tried all things commented out below, all makes no difference ##
    #fig.savefig(pngpath)

    #del(fig)
    #del(canvas)
    #del(ax)

    #import matplotlib.pyplot as plt
    #plt.close(fig)

    #import gc
    #gc.collect()

class ApplicationWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        self.setWindowTitle("application main window")

        self.file_menu = QtGui.QMenu('&File', self)
        self.file_menu.addAction('&Quit', self.fileQuit,
                                 QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
        self.menuBar().addMenu(self.file_menu)

        self.help_menu = QtGui.QMenu('&Help', self)

        self.main_widget = QtGui.QWidget(self)

        l = QtGui.QVBoxLayout(self.main_widget)
        sc = MyStaticMplCanvas(self.main_widget, width=5, height=4,
dpi=100)
        dc = QtGui.QPushButton('Save image')
        l.addWidget(sc)
        l.addWidget(dc)

        self.main_widget.setFocus()
        self.setCentralWidget(self.main_widget)

        self.statusBar().showMessage("All hail matplotlib!", 2000)
        self.connect(dc, QtCore.SIGNAL("clicked()"), save_png)

    def fileQuit(self):
        self.close()

    def closeEvent(self, ce):
        self.fileQuit()

qApp = QtGui.QApplication(sys.argv)

aw = ApplicationWindow()
aw.setWindowTitle("Try saving a simple png image")
aw.show()
sys.exit(qApp.exec_())

------------------------------------------------------------------------------

_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

--
View this message in context: http://www.nabble.com/memory-leak-with-PyQt4-plus-savefig-or-print_figure-tp24298299p24603899.html
Sent from the matplotlib - users mailing list archive at Nabble.com.

Ralph,

Perhaps time to migrate to Chaco API from Enthought? not sure if there is

Ubuntu support yet however.

Alex, I assume you did not mean to send this to the list…

Anyway, matplotlib is a central part of my application and is not going anywhere. The next step to try to fix this issue is compiling from trunk and seeing if anything changes. Unfortunately I do not have too much time at the moment so it may take a while to find the problem.

Cheers,
Ralf

···

On Wed, Jul 22, 2009 at 6:36 AM, Alexander Baker <baker.alexander@…287…> wrote:

Alex Baker

http://code.enthought.com/chaco/

Ralf Gommers-2 wrote:

Hi,

I am working on a PyQt4 application with some embedded MPL figures, and am

also trying to save some figures as png’s without displaying them. I am

observing huge memory increases (10s or 100s of Mb) the moment I try to

save

a png. I reproduced the issue by combining two mpl examples,

http://matplotlib.sourceforge.net/examples/user_interfaces/embedding_in_qt4.htmland

http://matplotlib.sourceforge.net/examples/api/agg_oo.html. Full code is

attached. When pressing the “save figure” button, memory usage shoots up,

multiple clicks keep sending it higher (although not monotonically).