Managing figure lifecycles in Matplotlib prevents memory leaks and ensures your plots render correctly. Understanding the difference between cla(), clf(), and close() is essential when creating multiple visualizations, especially in loops or long-running applications.
Understanding the Matplotlib Hierarchy
Matplotlib organizes visual elements in a three-level hierarchy, and each clearing method operates at a different level:
Figure (the window/canvas)
└── Axes (individual subplot)
└── Artists (lines, text, patches)| Method | Target Level | What It Does |
|---|---|---|
cla() |
Axes | Clears single subplot, preserves figure structure |
clf() |
Figure | Removes all subplots, keeps window open |
close() |
System | Destroys figure completely, releases memory |
Using cla() to Clear a Single Subplot
The cla() method clears the current axes (subplot) while maintaining the figure layout. This is useful for real-time updates or redrawing specific panels in a dashboard.
import matplotlib.pyplot as plt
import numpy as np
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
ax1.plot([1, 2, 3, 4], [1, 4, 2, 3], 'b-', label='Original')
ax1.set_title('Left Panel')
ax1.legend()
ax2.plot([1, 2, 3, 4], [3, 1, 4, 2], 'r-', label='Data')
ax2.set_title('Right Panel')
ax2.legend()
plt.tight_layout()
plt.savefig('before_cla.png')
ax1.cla()
ax1.plot([1, 2, 3, 4], [4, 3, 2, 1], 'g--', label='New Data')
ax1.set_title('Refreshed Left Panel')
ax1.legend()
plt.savefig('after_cla.png')
plt.show()Real-Time Animation Example
import matplotlib.pyplot as plt
import numpy as np
import time
fig, ax = plt.subplots()
plt.ion() # Enable interactive mode
for frame in range(50):
ax.cla() # Clear previous frame
x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(x + frame * 0.1)
ax.plot(x, y, 'b-')
ax.set_ylim(-1.5, 1.5)
ax.set_title(f'Frame {frame}')
plt.pause(0.05)
plt.ioff()
plt.show()Using clf() to Reset the Entire Figure
The clf() method clears the entire figure, removing all subplots and content while keeping the figure window open. Use this when you want to completely redesign a figure's layout.
import matplotlib.pyplot as plt
import numpy as np
plt.figure(figsize=(8, 6))
plt.subplot(2, 2, 1)
plt.plot([1, 2, 3], [1, 2, 3])
plt.subplot(2, 2, 2)
plt.plot([1, 2, 3], [3, 2, 1])
plt.suptitle('Original Layout')
plt.savefig('before_clf.png')
plt.clf()
plt.subplot(1, 1, 1) # Single plot instead of 2x2
x = np.linspace(0, 10, 100)
plt.plot(x, np.sin(x), 'r-', linewidth=2)
plt.title('Fresh Start - New Layout')
plt.xlabel('X axis')
plt.ylabel('Y axis')
plt.savefig('after_clf.png')
plt.show()Comparing cla() and clf()
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.plot([1, 2, 3])
ax2.plot([3, 2, 1])
ax1.cla()
print(f"After cla(): Figure has {len(fig.axes)} axes")
plt.clf()
print(f"After clf(): Figure has {len(fig.axes)} axes")Output:
After cla(): Figure has 2 axes
After clf(): Figure has 0 axesUsing close() to Release Memory
The close() function destroys a figure completely, releasing all associated memory. This is critical for batch processing and long-running scripts.
import matplotlib.pyplot as plt
import numpy as np
def generate_report_pages(data_list, output_dir):
"""Generate multiple plot files without memory leaks."""
for i, data in enumerate(data_list):
fig, ax = plt.subplots(figsize=(8, 6))
ax.plot(data['x'], data['y'])
ax.set_title(data['title'])
ax.set_xlabel('X')
ax.set_ylabel('Y')
filepath = f"{output_dir}/page_{i:03d}.png"
plt.savefig(filepath, dpi=150, bbox_inches='tight')
plt.close(fig)
print(f"Generated {len(data_list)} pages")
data_list = [
{'x': range(10), 'y': [i**2 for i in range(10)], 'title': f'Chart {n}'}
for n in range(100)
]
generate_report_pages(data_list, './output')Different Ways to Close Figures
import matplotlib.pyplot as plt
fig1 = plt.figure(num='First')
fig2 = plt.figure(num='Second')
fig3 = plt.figure(num=3)
plt.close(fig1)
plt.close('Second')
plt.close(3)
plt.figure()
plt.plot([1, 2, 3])
plt.close() # Closes the most recent figure
plt.figure()
plt.figure()
plt.figure()
print(f"Open figures: {plt.get_fignums()}")
plt.close('all')
print(f"After close('all'): {plt.get_fignums()}")Output:
Open figures: [1, 2, 3]
After close('all'): []Memory Management Best Practices
Batch Processing Template
import matplotlib.pyplot as plt
import numpy as np
def create_batch_plots(n_plots):
"""Safely generate multiple plots."""
for i in range(n_plots):
try:
fig, ax = plt.subplots()
x = np.random.randn(100)
ax.hist(x, bins=20)
ax.set_title(f'Distribution {i}')
plt.savefig(f'hist_{i:04d}.png')
finally:
plt.close(fig)
create_batch_plots(50)Using Context Manager Pattern
import matplotlib.pyplot as plt
from contextlib import contextmanager
@contextmanager
def managed_figure(*args, **kwargs):
"""Context manager for automatic figure cleanup."""
fig = plt.figure(*args, **kwargs)
try:
yield fig
finally:
plt.close(fig)
for i in range(100):
with managed_figure(figsize=(8, 6)) as fig:
ax = fig.add_subplot(111)
ax.plot([1, 2, 3], [i, i*2, i*3])
plt.savefig(f'managed_{i:03d}.png')Quick Reference
| Scenario | Method | Example |
|---|---|---|
| Update single subplot | ax.cla() |
Real-time sensor display |
| Reset figure layout | plt.clf() |
Interactive dashboard refresh |
| Batch file generation | plt.close(fig) |
Report generation scripts |
| End of script cleanup | plt.close('all') |
Notebook cells, test teardown |
| Animation frames | ax.cla() |
Live data visualization |
Understanding when to use each method ensures your visualizations render correctly while keeping memory usage under control: this is especially important in production environments and data pipelines.