Memory leak when destroying Tk frame containing a figure

Hello!

I’m writing an application that will show different plots on it’s GUI. In order to switch between the different plot types I’d like to destroy the first plot and to create a new afterwards. I stumbled into a memory leak since I don’t know how to close matplotlib figures the clean way.

I wrote a small test programm. Pressing the button ‘create’ creates a figure and ‘delete’ should destroy it.
Since the graph class is derived from the Tix.Frame class I would expect that destroying the Frame would also remove all matplot stuff. But when I do not implement my own destroy() method in the graph class, destroying the Frame shows absolutely no effect. The plot simply stays on the screen.
When I overload the Tix.Frame.destroy() method with my own implementation, as shown below, the plot disappears but not all memory is being released. When creating and deleting figures, the amount of memory python needs is constantly growing and python eventually crashes.

I tried to find a solution on the internet but I found nothing really helpful so far. All examples I found just display something and then just exit.

I appreciate any help!

···

import matplotlib
matplotlib.use(‘TkAgg’)

from numpy import arange, sin, pi
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure

import Tix
import sys

def destroy(e): sys.exit()

root = Tix.Tk()

class graph(Tix.Frame):
def init(self, master, **kw):
Tix.Frame.init(self, master, **kw)

    self.f = Figure(figsize=(5,4), dpi=100)
    self.a = self.f.add_subplot(111)
    t = arange(0.0,3.0,0.01)
    s = sin(2*pi*t)
    self.a.plot(t,s)

    self.canvas = FigureCanvasTkAgg(self.f, master=self.master)
    self.canvas.show()
    self.canvas.get_tk_widget().pack(side=Tix.TOP, fill=Tix.BOTH, expand=1)

    self.toolbar = NavigationToolbar2TkAgg(self.canvas, root )
    self.toolbar.update()
    self.canvas._tkcanvas.pack(side=Tix.TOP, fill=Tix.BOTH, expand=1)
   
def destroy(self):
    Tix.Frame.destroy(self)
    self.toolbar.destroy()
    self.canvas._tkcanvas.destroy()

class ui(Tix.Frame):

g = None

def __init__(self, master, **kw):
    Tix.Frame.__init__(self, master, **kw)
   
    self.b = Tix.Button(self, text='create', command=self.create)
    self.b.pack()
   
    self.b2 = Tix.Button(self, text='delete', command=self.delete)
    self.b2.pack()

def delete(self):
    try:
        self.g.destroy()
    except:
        pass
   
def create(self):
    self.delete()
    self.g = graph(root)

ui(root).pack()
root.mainloop()

GRATIS für alle WEB.DE-Nutzer: Die maxdome Movie-FLAT!
Jetzt freischalten unter http://movieflat.web.de

Have you tried explicitly calling .clf() on the matplotlib Figure object from your Tix.Frame.destroy callback?

Mike

I already had my destroy() method look like this:

    def destroy(self):
        self.f.clf()
        Tix.Frame.destroy(self)
        self.toolbar.destroy()
        self.canvas._tkcanvas.destroy()

But it makes no difference.

Stephan

···

Am 08.02.2010 17:15, schrieb Michael Droettboom:

Have you tried explicitly calling .clf() on the matplotlib Figure object from your Tix.Frame.destroy callback?

Mike

Calling the garbage collector (gc.collect()) also makes no difference.
Even deleting all references manually and dropping the toolbar code
doesn't do the trick.

···

Am 09.02.2010 16:19, schrieb Stephan Markus:

I already had my destroy() method look like this:

    def destroy(self):
        self.f.clf()
        Tix.Frame.destroy(self)
        self.toolbar.destroy()
        self.canvas._tkcanvas.destroy()

But it makes no difference.

Stephan

Am 08.02.2010 17:15, schrieb Michael Droettboom:
  

Have you tried explicitly calling .clf() on the matplotlib Figure object from your Tix.Frame.destroy callback?

Mike