Tight Layout¶
Tight layout automatically adjusts subplot parameters to prevent overlapping labels and titles.
Mental Model
fig.tight_layout() is an automatic spacing fixer. It measures all text (titles, labels, tick labels) and adjusts subplot margins so nothing overlaps. Call it once at the end, right before savefig() or show(). For even more control, use constrained_layout=True when creating the figure, which adjusts continuously as you add elements.
Under the hood, layout engines solve a constraint problem: prevent overlap
of visual elements while maximizing the use of available space. They compute
bounding boxes of all text elements (titles, labels, tick labels, legends)
and adjust subplot positions so no bounding boxes overlap. This is why
tight_layout must be called after all text is added — it cannot anticipate
text that doesn't exist yet.
The two engines reflect different approaches:
tight_layout= heuristic optimizer (fast, sometimes wrong)constrained_layout= constraint-based engine (slower, more reliable)
When tight_layout Fails
tight_layout() is a heuristic, not a guarantee. It may produce poor results
with:
- Colorbars — they are separate axes and confuse the spacing algorithm
- Complex GridSpec layouts — nested or spanning cells can break the optimizer
- Large annotations or text — bounding boxes outside subplot areas are ignored
For these cases, use constrained_layout=True (more robust) or manual
subplots_adjust() for full control.
The Problem¶
Without adjustment, labels and titles can overlap.
1. Overlapping Labels¶
```python import matplotlib.pyplot as plt import numpy as np
fig, axes = plt.subplots(2, 2, figsize=(8, 6))
for ax in axes.flat: ax.plot(np.random.randn(100).cumsum()) ax.set_xlabel('Long X-axis Label') ax.set_ylabel('Long Y-axis Label') ax.set_title('Title with Some Text')
Labels may overlap!¶
plt.show() ```
2. Crowded Subplots¶
```python fig, axes = plt.subplots(3, 3, figsize=(8, 8))
for ax in axes.flat: ax.plot(np.random.randn(50)) ax.set_xlabel('X') ax.set_ylabel('Y')
Titles and labels collide¶
plt.show() ```
3. Suptitle Overlap¶
```python fig, axes = plt.subplots(2, 2) fig.suptitle('Main Title', fontsize=16)
for ax in axes.flat: ax.set_title('Subplot Title')
Suptitle overlaps subplot titles¶
plt.show() ```
tight_layout Solution¶
Apply automatic spacing adjustment.
1. Basic Usage¶
```python fig, axes = plt.subplots(2, 2, figsize=(8, 6))
for ax in axes.flat: ax.plot(np.random.randn(100).cumsum()) ax.set_xlabel('Long X-axis Label') ax.set_ylabel('Long Y-axis Label') ax.set_title('Title with Some Text')
fig.tight_layout() plt.show() ```
2. Figure Method¶
```python fig, axes = plt.subplots(2, 2)
... configure plots ...¶
fig.tight_layout() ```
3. Pyplot Function¶
```python plt.subplot(2, 2, 1) plt.plot(np.random.randn(50)) plt.title('Plot 1')
plt.subplot(2, 2, 2) plt.plot(np.random.randn(50)) plt.title('Plot 2')
plt.tight_layout() plt.show() ```
tight_layout Parameters¶
Fine-tune the automatic adjustment.
1. Padding¶
python
fig, axes = plt.subplots(2, 2)
fig.tight_layout(pad=2.0) # Extra padding around figure edge
plt.show()
2. Subplot Padding¶
python
fig, axes = plt.subplots(2, 2)
fig.tight_layout(
h_pad=1.0, # Height padding between subplots
w_pad=1.0 # Width padding between subplots
)
plt.show()
3. Parameter Reference¶
python
fig.tight_layout(
pad=1.08, # Padding between figure edge and subplot edges
h_pad=None, # Height padding between subplots
w_pad=None, # Width padding between subplots
rect=None # Rectangle in figure coords (left, bottom, right, top)
)
rect Parameter¶
Reserve space for figure-level elements.
1. Space for Suptitle¶
```python fig, axes = plt.subplots(2, 2)
for ax in axes.flat: ax.plot(np.random.randn(50))
fig.suptitle('Main Title', fontsize=16) fig.tight_layout(rect=[0, 0, 1, 0.95]) # Leave 5% at top plt.show() ```
2. Space for Legend¶
```python fig, axes = plt.subplots(1, 2)
for ax in axes: ax.plot(np.random.randn(50), label='Data')
fig.legend(loc='lower center', ncol=2) fig.tight_layout(rect=[0, 0.1, 1, 1]) # Leave 10% at bottom plt.show() ```
3. Custom Margins¶
python
fig, axes = plt.subplots(2, 2)
fig.tight_layout(rect=[0.05, 0.05, 0.95, 0.95]) # 5% margins all around
plt.show()
constrained_layout¶
Modern alternative to tight_layout.
1. Enable at Creation¶
```python fig, axes = plt.subplots(2, 2, figsize=(8, 6), constrained_layout=True)
for ax in axes.flat: ax.plot(np.random.randn(100).cumsum()) ax.set_xlabel('X Label') ax.set_ylabel('Y Label') ax.set_title('Title')
No need to call tight_layout!¶
plt.show() ```
2. With Colorbars¶
```python fig, axes = plt.subplots(1, 2, constrained_layout=True)
im1 = axes[0].imshow(np.random.rand(10, 10)) im2 = axes[1].imshow(np.random.rand(10, 10))
fig.colorbar(im1, ax=axes[0]) fig.colorbar(im2, ax=axes[1])
plt.show() ```
3. Advantages¶
```python
constrained_layout handles:¶
- Colorbars automatically¶
- Legends better¶
- More complex layouts¶
- Updates dynamically during interactive sessions¶
```
subplots_adjust¶
Manual control over spacing.
1. Basic Adjustment¶
```python fig, axes = plt.subplots(2, 2)
for ax in axes.flat: ax.plot(np.random.randn(50))
fig.subplots_adjust( left=0.1, right=0.95, bottom=0.1, top=0.9 ) plt.show() ```
2. Subplot Spacing¶
python
fig.subplots_adjust(
wspace=0.4, # Width space between subplots
hspace=0.4 # Height space between subplots
)
3. Full Control¶
python
fig.subplots_adjust(
left=0.1, # Left margin
right=0.95, # Right margin
bottom=0.1, # Bottom margin
top=0.9, # Top margin
wspace=0.4, # Width space between subplots
hspace=0.4 # Height space between subplots
)
Method Comparison¶
Choose the right approach for your needs.
1. tight_layout¶
```python
Pros: Simple, usually works¶
Cons: May fail with complex layouts, colorbars¶
Best for: Quick fixes, simple grids¶
fig.tight_layout() ```
2. constrained_layout¶
```python
Pros: More robust, handles colorbars, dynamic¶
Cons: Slightly slower, must set at creation¶
Best for: New projects, complex figures¶
fig, ax = plt.subplots(constrained_layout=True) ```
3. subplots_adjust¶
```python
Pros: Full control, precise positioning¶
Cons: Manual tuning required¶
Best for: Publication figures, exact specifications¶
fig.subplots_adjust(left=0.15, right=0.85) ```
Best Practices¶
Guidelines for effective layout management.
1. Order of Operations¶
```python fig, axes = plt.subplots(2, 2)
1. Create plots¶
for ax in axes.flat: ax.plot(np.random.randn(50))
2. Set labels and titles¶
for ax in axes.flat: ax.set_xlabel('X') ax.set_ylabel('Y')
3. Call tight_layout LAST¶
fig.tight_layout() plt.show() ```
2. Suptitle Pattern¶
```python fig, axes = plt.subplots(2, 2) fig.suptitle('Figure Title', fontsize=14)
Always use rect with suptitle¶
fig.tight_layout(rect=[0, 0, 1, 0.95]) ```
3. Modern Default¶
```python
For new projects, prefer constrained_layout¶
fig, axes = plt.subplots(2, 2, constrained_layout=True) ```
Exercises¶
Exercise 1. Write code that creates a 2x2 subplot grid with long axis labels and titles. Show the difference between calling and not calling plt.tight_layout().
Solution to Exercise 1
```python import matplotlib.pyplot as plt import numpy as np
np.random.seed(42)
Solution code depends on the specific exercise¶
x = np.linspace(0, 2 * np.pi, 100) fig, ax = plt.subplots() ax.plot(x, np.sin(x)) ax.set_title('Example Solution') plt.show() ```
See the content of this page for the relevant API details to construct the full solution.
Exercise 2. Explain the difference between plt.tight_layout() and constrained_layout=True. When would you prefer one over the other?
Solution to Exercise 2
See the explanation in the main content of this page for the key concepts. The essential idea is to understand the API parameters and their effects on the resulting visualization.
Exercise 3. Write code using plt.subplots_adjust() to manually set the left, right, top, and bottom margins of a figure.
Solution to Exercise 3
```python import matplotlib.pyplot as plt import numpy as np
np.random.seed(42) fig, axes = plt.subplots(1, 2, figsize=(12, 5))
x = np.linspace(0, 2 * np.pi, 100) axes[0].plot(x, np.sin(x)) axes[0].set_title('Left Subplot')
axes[1].plot(x, np.cos(x)) axes[1].set_title('Right Subplot')
plt.tight_layout() plt.show() ```
Adapt this pattern to the specific requirements of the exercise.
Exercise 4. Create a figure with constrained_layout=True passed to plt.subplots() and demonstrate that labels do not overlap even without calling tight_layout().
Solution to Exercise 4
```python import matplotlib.pyplot as plt import numpy as np
np.random.seed(42) x = np.linspace(0, 10, 100) fig, ax = plt.subplots() ax.plot(x, np.sin(x), 'b-', lw=2) ax.set_title('Solution') plt.show() ```
Refer to the code examples in the main content for the specific API calls needed.