When to use cla(), clf() or close() for clearing a plot
Asked Answered
H

4

749

Matplotlib offers these functions:

cla()   # Clear axis
clf()   # Clear figure
close() # Close a figure window

When should I use each function and what exactly does it do?

Hallock answered 21/11, 2011 at 14:38 Comment(0)
J
934

They all do different things, since matplotlib uses a hierarchical order in which a figure window contains a figure which may consist of many axes. Additionally, there are functions from the pyplot interface and there are methods on the Figure class. I will discuss both cases below.

pyplot interface

pyplot is a module that collects a couple of functions that allow matplotlib to be used in a functional manner. I here assume that pyplot has been imported as import matplotlib.pyplot as plt. In this case, there are three different commands that remove stuff:

See matplotlib.pyplot Functions:

  • plt.cla() clears an axis, i.e. the currently active axis in the current figure. It leaves the other axes untouched.
  • plt.clf() clears the entire current figure with all its axes, but leaves the window opened, such that it may be reused for other plots.
  • plt.close() closes a window, which will be the current window, if not specified otherwise.

Which functions suits you best depends thus on your use-case.

The close() function furthermore allows one to specify which window should be closed. The argument can either be a number or name given to a window when it was created using figure(number_or_name) or it can be a figure instance fig obtained, i.e., usingfig = figure(). If no argument is given to close(), the currently active window will be closed. Furthermore, there is the syntax close('all'), which closes all figures.

methods of the Figure class

Additionally, the Figure class provides methods for clearing figures. I'll assume in the following that fig is an instance of a Figure:

fig.clf() clears the entire figure. This call is equivalent to plt.clf() only if fig is the current figure.

fig.clear() is a synonym for fig.clf()

Note that even del fig will not close the associated figure window. As far as I know the only way to close a figure window is using plt.close(fig) as described above.

Jer answered 22/11, 2011 at 14:54 Comment(0)
S
117

There is just a caveat that I discovered today. If you have a function that is calling a plot a lot of times you better use plt.close(fig) instead of fig.clf() somehow the first does not accumulate in memory. In short if memory is a concern use plt.close(fig) (Although it seems that there are better ways, go to the end of this comment for relevant links).

So the the following script will produce an empty list:

for i in range(5):
    fig = plot_figure()
    plt.close(fig)
# This returns a list with all figure numbers available
print(plt.get_fignums())

Whereas this one will produce a list with five figures on it.

for i in range(5):
    fig = plot_figure()
    fig.clf()
# This returns a list with all figure numbers available
print(plt.get_fignums())

From the documentation above is not clear to me what is the difference between closing a figure and closing a window. Maybe that will clarify.

If you want to try a complete script there you have:

import numpy as np
import matplotlib.pyplot as plt
x = np.arange(1000)
y = np.sin(x)

for i in range(5):
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    ax.plot(x, y)
    plt.close(fig)

print(plt.get_fignums())

for i in range(5):
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    ax.plot(x, y)
    fig.clf()

print(plt.get_fignums())

If memory is a concern somebody already posted a work-around in SO see: Create a figure that is reference counted

Scathing answered 26/10, 2015 at 10:19 Comment(4)
Thanks for the helpful cross-reference to the reference counting question. That's exactly how Matplotlib should already work. It's equally terrifying and appalling that figures are never garbage collected under the standard pyplot API.Ison
Nevertheless, I have found that if one has to make animations (for example some 2D contour/pcolormesh maps) it is better to clear the figure and draw new fields instead of closing old and making new figure panels. The speed will be completely different.Greatnephew
Thank you, my problem solved for animation, i had the axes duplication on plot it removed by plt.cla() inside animate function.Ontine
If you use plt.clf() followed by plt.close() then the memory is freed correctly. Just using plt.close() still leads to residual memory increase per plot opened.Caritacaritas
A
25

plt.cla() means clear current axis

plt.clf() means clear current figure

also, there's plt.gca() (get current axis) and plt.gcf() (get current figure)

Read more here: Matplotlib, Pyplot, Pylab etc: What's the difference between these and when to use each?

Axiomatic answered 23/10, 2018 at 2:14 Comment(0)
Y
6

When to use cla(), clf() or close()

As David Zwicker explained, all these methods clear different things. This post adds some examples to help clarify when to use them.

  • If you want to re-use particular configurations of a figure (facecolor, dpi, layout etc.) for another figure, use fig.clf() to clear the current objects (including Axes) on the figure. Note that this doesn't delete a previously instantiated Figure instance, but only clears objects on it. So in the following code, a single Figure instance is re-used to produce 2 image files.

    fig, ax = plt.subplots()        # instantiate a Figure and an Axes
    ax.plot([0,1,2])                # draw a line plot
    fig.savefig('images/img1.png')
    fig.clf()                       # clear Figure (removes Axes)
    ax = fig.add_subplot()          # add new Axes to previously instantiated `fig`
    ax.plot([1,2,0,0,2,1], 'o')     # draw a scatter plot
    fig.savefig('images/img2.png')
    

    Since fig.clf() removes the Axes, it's important to add a new one on it in order to plot something.

  • If you want to re-use a figure but change an Axes on it, then use ax.cla() to clear the current objects (e.g. ticks, titles, plots etc.) on the Axes. In particular, the position of an Axes on a figure is an important attribute that could be re-used (e.g. the figure has a small Axes could be superimposed on a larger Axes).

  • If want to close a figure window, use plt.close(). This is especially useful if you use an IDE with an interactive mode such as Jupyter or Spyder and you don't want to see the figure(s) your script creates. If you use a Python shell such as IDLE (that comes with a Python installation), then it literally closes the window that shows a figure. Even though it closes the window, the Figure instance is still in memory along with whatever objects defined on it. For example in the following code, even though fig is closed, it can still be worked on. However, because the figure/Axes was not cleared, whatever was in fig persists.

    fig, ax = plt.subplots()        # instantiate a Figure and an Axes
    ax.plot([0,1,2])                # draw a line plot
    fig.savefig('images/img1.png')  # save the line plot
    plt.close(fig)                  # close `fig`
    ax.plot([1,2,0,0,2,1], 'o')     # draw a scatter plot on top of the previously plotted lineplot
    fig.savefig('images/img2.png')  # save scatter + line plot
    

Memory usage

Heberto Mayorquin points out that plt.close() saves memory. However, as the following memory allocation traces show, if a lot of similar images need to be created in a loop, clearing with clf() or cla() is actually more memory efficient than closing a window and creating a new figure instance with plt.close().

However, there's a caveat that since cla()/clf() are meant to re-use a previously defined Axes/Figure, it's important to define the Figure object to be re-used outside the loop (that creates image files). I also included "wrong" ways to use cla() and clf() in the test (where a new Figure instance is created every time a new figure is drawn) which are indeed more costly than creating a new Figure and closing it in a loop.

close:
current memory usage is 12,456 KB; peak was 13,402 KB.
======================================================
cla:
current memory usage is 899 KB; peak was 1,451 KB.
======================================================
clf:
current memory usage is 3,806 KB; peak was 8,061 KB.
======================================================
clf_wrong:
current memory usage is 7,392 KB; peak was 10,494 KB.
======================================================
cla_wrong:
current memory usage is 29,174 KB; peak was 29,650 KB.
======================================================

Code used to the produce the above result:

import os
import tracemalloc
import matplotlib.pyplot as plt

def close(n):
    for i in range(n):
        fig = plt.figure(facecolor='white', figsize=(6,3), dpi=36)
        ax = fig.add_subplot()
        ax.plot([100, 0, i])
        fig.savefig(f'{i}.png')
        plt.close(fig)


def cla(n):
    fig = plt.figure(facecolor='white', figsize=(6,3), dpi=36)
    ax = fig.add_subplot()
    for i in range(n):
        ax.plot([100, 0, i])
        fig.savefig(f'{i}.png')
        ax.cla()


def clf(n):
    fig = plt.figure(facecolor='white', figsize=(6,3), dpi=36)
    for i in range(n):
        ax = fig.add_subplot()
        ax.plot([100, 0, i])
        fig.savefig(f'{i}.png')
        fig.clf()


def cla_wrong(n):
    for i in range(n):
        fig = plt.figure(facecolor='white', figsize=(6,3), dpi=36)
        ax = fig.add_subplot()
        ax.plot([100, 0, i])
        fig.savefig(f'{i}.png')
        ax.cla()


def clf_wrong(n):
    for i in range(n):
        fig = plt.figure(facecolor='white', figsize=(6,3), dpi=36)
        ax = fig.add_subplot()
        ax.plot([100, 0, i])
        fig.savefig(f'{i}.png')
        fig.clf()


if __name__ == '__main__':
    
    for func in (close, cla, clf, clf_wrong, cla_wrong):
        tracemalloc.start()
        func(100)
        size, peak = tracemalloc.get_traced_memory()
        tracemalloc.stop()
        # delete the saved image files
        for f in os.listdir():
            if f.endswith('.png'):
                os.remove(f)
        print(f"{func.__name__}:\ncurrent memory usage is {size/1024:,.0f} KB; \
peak was {peak/1024:,.0f} KB.")
        print("======================================================")
Yeomanly answered 2/10, 2023 at 23:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.