views:

897

answers:

2

I've created a small PyQt based utility in Python that creates PNG graphs using matplotlib when a user clicks a button. Everything works well during the first few clicks, however each time an image is created, the application's memory footprint grows about 120 MB, eventually crashing Python altogether.

How can I recover this memory after a graph is created? I've included a simplified version of my code here:

import datetime as dt
from datetime import datetime 
import os
import gc
# For Graphing
import matplotlib
from pylab import figure, show, savefig
from matplotlib import figure as matfigure
from matplotlib.dates import MonthLocator, WeekdayLocator, DateFormatter, DayLocator
from matplotlib.ticker import MultipleLocator
import matplotlib.pyplot as plot
import matplotlib.ticker as ticker
# For GUI
import sys
from PyQt4 import QtGui, QtCore

class HyperGraph(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.setWindowTitle('Title')
        self.create_widgets()

    def create_widgets(self):
        grid = QtGui.QGridLayout()
        self.generate_button = QtGui.QPushButton("Generate Graph", self)
        grid.addWidget(self.generate_button, 1, 1)
        QtCore.QObject.connect(self.generate_button, QtCore.SIGNAL("clicked()"), self.generate_graph)

    def generate_graph(self):
        try:
            fig = figure()
            ax = fig.add_axes([1,1,1,1])

            # set title
            ax.set_title('Title')

            # configure x axis
            plot.xlim(dt.date.today() - dt.timedelta(days=180), dt.date.today())
            ax.set_xlabel('Date')
            fig.set_figwidth(100)

            # configure y axis
            plot.ylim(0, 200)
            ax.set_ylabel('Price')
            fig.set_figheight(30)

            # export the graph to a png file
            plot.savefig('graph.png')

        except:
            print 'Error'

        plot.close(fig)
        gc.collect()

app = QtGui.QApplication(sys.argv)
hyper_graph = HyperGraph()
hyper_graph.show()
sys.exit(app.exec_())

The plot.savefig('graph.png') command seems to be what's gobbling up the memory.

I'd greatly appreciate any help!

+3  A: 

It seems that some backends are leaking memory. Try setting your backend explicitly, e.g.

import matplotlib
matplotlib.use('Agg') # before import pylab
import pylab
wierob
Thanks! This worked very well. I'm going to have to look into more details of your answer.
Eric the Red
+1  A: 

The pyplot interface is meant for easy interactive use, but for embedding in an application the object-oriented API is better. For example, pyplot keeps track of all figures you have created. Your plot.close(figure) should get rid of them, but maybe it doesn't get executed -- try putting it inside finally or reusing the same figure object.

See this example of embedding matplotlib in a PyQt4 application using the object-oriented API. It's more work, but since everything is explicit, you shouldn't get memory leaks from the behind-the-scenes automation that pyplot does.

Jouni K. Seppänen