How to Change Figure Size in Matplotlib
Figure size directly impacts the readability and professionalism of your visualizations. A plot that looks perfect on your laptop screen might become illegible when inserted into a presentation or...
Key Insights
- Figure size in Matplotlib is specified in inches as a tuple (width, height), with the default being (6.4, 4.8) inches—set it at creation with
figsizeparameter or modify later withset_size_inches() - The
plt.subplots()approach is preferred overplt.figure()for modern code because it returns both figure and axes objects, giving you explicit control over all plot elements - DPI (dots per inch) multiplied by figure size determines pixel dimensions: a 10×6 inch figure at 100 DPI produces a 1000×600 pixel image, critical for ensuring plots meet publication requirements
Introduction
Figure size directly impacts the readability and professionalism of your visualizations. A plot that looks perfect on your laptop screen might become illegible when inserted into a presentation or rejected by a journal for not meeting dimension requirements. Matplotlib gives you precise control over figure dimensions, but the multiple approaches can be confusing.
The two fundamental approaches are setting size at creation (recommended) or modifying existing figures (useful when working with code you can’t easily refactor). Understanding both methods and when to use them will save you from the frustration of regenerating plots or wrestling with layout issues.
Setting Figure Size with plt.figure()
The plt.figure() function creates a new figure and accepts a figsize parameter that takes a tuple of (width, height) in inches. Yes, inches—a quirk inherited from Matplotlib’s print-oriented origins. The default size is (6.4, 4.8) inches.
import matplotlib.pyplot as plt
import numpy as np
# Create figure with custom size
plt.figure(figsize=(10, 6))
# Generate sample data
x = np.linspace(0, 10, 100)
y = np.sin(x)
# Create plot
plt.plot(x, y, linewidth=2)
plt.title('Sine Wave - Custom Figure Size')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
This approach is straightforward but has limitations. You’re using the pyplot state machine, which implicitly manages the current figure and axes. For simple scripts, this works fine. For complex visualizations or reusable code, you’ll want more control.
Setting Figure Size with plt.subplots()
The plt.subplots() function is the modern, preferred approach. It creates a figure and one or more subplots in a single call, returning explicit references to both. This gives you direct control without relying on pyplot’s implicit state.
import matplotlib.pyplot as plt
import numpy as np
# Create figure and axes with custom size
fig, ax = plt.subplots(figsize=(12, 8))
# Generate data
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
# Create plots using the axes object
ax.plot(x, y1, label='sin(x)', linewidth=2)
ax.plot(x, y2, label='cos(x)', linewidth=2)
ax.set_title('Trigonometric Functions', fontsize=14)
ax.set_xlabel('X-axis', fontsize=12)
ax.set_ylabel('Y-axis', fontsize=12)
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
This pattern scales better. When you need multiple subplots, the syntax remains consistent:
# Create 2x2 grid of subplots
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# axes is now a 2D array you can iterate over
for i, ax in enumerate(axes.flat):
ax.plot(np.random.randn(100))
ax.set_title(f'Subplot {i+1}')
plt.tight_layout()
plt.show()
Modifying Existing Figure Size
Sometimes you need to change the size of a figure after creation—perhaps you’re working with a plotting function that creates its own figure, or you’re debugging and want to quickly resize without re-running expensive computations.
The set_size_inches() method handles this:
import matplotlib.pyplot as plt
import numpy as np
# Create figure with default size
fig, ax = plt.subplots()
# Create initial plot
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x))
ax.set_title('Initial Size')
# Modify the figure size
fig.set_size_inches(8, 6)
# The forward parameter forces the GUI to update
# fig.set_size_inches(8, 6, forward=True)
plt.tight_layout()
plt.show()
The forward parameter (default True) controls whether the change propagates to the display window. Set it to False if you’re only changing size for saving, not display.
Figure Size in Object-Oriented vs. Pyplot Interfaces
Matplotlib offers two interfaces: the object-oriented (OO) interface and the pyplot state machine. Understanding both helps you read existing code and choose the right approach.
Object-Oriented Interface (Recommended):
import matplotlib.pyplot as plt
import numpy as np
# Explicit figure and axes creation
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(111)
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x))
ax.set_title('OO Interface')
# Modify size using the figure object
fig.set_size_inches(12, 7)
plt.show()
Pyplot Interface (Quick and Dirty):
import matplotlib.pyplot as plt
import numpy as np
# Implicit figure creation
plt.plot(np.linspace(0, 10, 100), np.sin(np.linspace(0, 10, 100)))
plt.title('Pyplot Interface')
# Get current figure and modify
plt.gcf().set_size_inches(10, 6)
plt.show()
Use the OO interface for production code, libraries, and complex visualizations. Use pyplot for quick exploratory analysis and simple scripts. The OO interface makes dependencies explicit and avoids the global state issues that plague pyplot-heavy code.
Practical Considerations
Figure size alone doesn’t determine output quality—DPI (dots per inch) matters equally. The pixel dimensions of your saved figure equal (width_inches * DPI, height_inches * DPI).
import matplotlib.pyplot as plt
import numpy as np
# Create figure with size and DPI specified
fig, ax = plt.subplots(figsize=(10, 6), dpi=100)
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x))
ax.set_title('Figure Size with DPI Control')
# This creates a 1000x600 pixel image (10*100 x 6*100)
plt.savefig('plot_100dpi.png', dpi=100, bbox_inches='tight')
# Same figure size, higher resolution (1500x900 pixels)
plt.savefig('plot_150dpi.png', dpi=150, bbox_inches='tight')
plt.show()
Aspect Ratio Considerations:
- 16:9 (e.g., 16×9 inches): Ideal for presentations and widescreen displays
- 4:3 (e.g., 12×9 inches): Traditional presentations and publications
- Golden ratio (~1.618:1, e.g., 10×6.18 inches): Aesthetically pleasing for many contexts
- Square (e.g., 8×8 inches): Useful for correlation matrices and certain scientific plots
Default DPI is 100 for display and 100 for savefig(). For print publications, use 300 DPI minimum. For web, 72-100 DPI usually suffices.
Common Use Cases
Different contexts demand different figure sizes. Here’s a practical reference:
import matplotlib.pyplot as plt
import numpy as np
# Generate sample data once
x = np.linspace(0, 10, 100)
y = np.sin(x)
# Journal publication (two-column format)
fig_journal, ax_journal = plt.subplots(figsize=(3.5, 2.5), dpi=300)
ax_journal.plot(x, y)
ax_journal.set_title('Journal (3.5" × 2.5", 300 DPI)', fontsize=8)
plt.savefig('journal_plot.png', dpi=300, bbox_inches='tight')
# Presentation slide (16:9)
fig_presentation, ax_presentation = plt.subplots(figsize=(12, 6.75), dpi=100)
ax_presentation.plot(x, y, linewidth=3)
ax_presentation.set_title('Presentation (16:9)', fontsize=18)
plt.savefig('presentation_plot.png', dpi=100, bbox_inches='tight')
# Web dashboard
fig_web, ax_web = plt.subplots(figsize=(8, 5), dpi=96)
ax_web.plot(x, y)
ax_web.set_title('Web Dashboard (8" × 5", 96 DPI)', fontsize=12)
plt.savefig('web_plot.png', dpi=96, bbox_inches='tight')
# High-resolution poster
fig_poster, ax_poster = plt.subplots(figsize=(20, 15), dpi=300)
ax_poster.plot(x, y, linewidth=4)
ax_poster.set_title('Poster (20" × 15", 300 DPI)', fontsize=24)
plt.savefig('poster_plot.png', dpi=300, bbox_inches='tight')
plt.show()
Quick Reference Table:
- Jupyter notebooks: (10, 6) at 100 DPI for inline display
- PowerPoint slides: (10, 7.5) or (12, 6.75) for 4:3 or 16:9 respectively
- Academic papers: (3.5, 2.5) for single column, (7, 5) for double column at 300 DPI
- Posters: (24, 18) or larger at 300 DPI
- Social media: (10, 10) square at 100 DPI for Instagram, (16, 9) for Twitter
Always use bbox_inches='tight' when saving to prevent clipping of labels and titles. Combine this with plt.tight_layout() before saving for best results.
The key to mastering figure sizing is understanding your output medium’s requirements before you start plotting. Set the size correctly from the beginning, and you’ll avoid the frustration of reformatting or regenerating visualizations later.