Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a figure that is reference counted

It seems that the standard way of creating a figure in matplotlib doesn't behave as I'd expect in python: by default calling fig = matplotlib.figure() in a loop will hold on to all the figures created, and eventually run out of memory.

There are quite a few posts which deal with workarounds, but requiring explicit calls to matplotlib.pyplot.close(fig) seems a bit hackish. What I'd like is a simple way to make fig reference counted, so I won't have to worry about memory leaks. Is there some way to do this?

like image 508
Shep Avatar asked May 02 '13 09:05

Shep


3 Answers

If you create the figure without using plt.figure, then it should be reference counted as you expect. For example (This is using the non-interactive Agg backend, as well.)

from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure

# The pylab figure manager will be bypassed in this instance.
# This means that `fig` will be garbage collected as you'd expect.
fig = Figure()
canvas = FigureCanvas(fig)
ax = fig.add_subplot(111)
like image 51
Joe Kington Avatar answered Nov 20 '22 11:11

Joe Kington


If you're only going to be saving figures rather than displaying them, you can use:

def savefig(*args, **kwargs):
    plt.savefig(*args, **kwargs)
    plt.close(plt.gcf())

This is arguably no less hacky, but whatever.

like image 38
1'' Avatar answered Nov 20 '22 13:11

1''


If you want to profit from the use of pyplot and have the possibility to wrap the figure in a class of your own, you can use the __del__ method of your class to close the figure.

Something like:

import matplotlib.pyplot as plt

class MyFigure:
  """This is my class that just wraps a matplotlib figure"""
  def __init__(self):
    # Get a new figure using pyplot
    self.figure = plt.figure()

  def __del__(self):
    # This object is getting deleted, close its figure
    plt.close(self.figure)

Whenever the garbage collector decides to delete your figure because it is inaccessible, the matplotlib figure will be closed.

However note that if someone has grabbed the figure (but not your wrapper) they might be annoyed that you closed it. It probably can be solved with some more thought or imposing some restrictions on usage.

like image 1
Pol Febrer Avatar answered Nov 20 '22 12:11

Pol Febrer