Skip to content

Tight Layout

Tight layout automatically adjusts subplot parameters to prevent overlapping labels and titles.

The Problem

Without adjustment, labels and titles can overlap.

1. Overlapping Labels

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

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

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

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

fig, axes = plt.subplots(2, 2)
# ... configure plots ...
fig.tight_layout()

3. Pyplot Function

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

fig, axes = plt.subplots(2, 2)
fig.tight_layout(pad=2.0)  # Extra padding around figure edge
plt.show()

2. Subplot Padding

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

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

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

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

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

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

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

# constrained_layout handles:
# - Colorbars automatically
# - Legends better
# - More complex layouts
# - Updates dynamically during interactive sessions

subplots_adjust

Manual control over spacing.

1. Basic Adjustment

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

fig.subplots_adjust(
    wspace=0.4,  # Width space between subplots
    hspace=0.4   # Height space between subplots
)

3. Full Control

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

# Pros: Simple, usually works
# Cons: May fail with complex layouts, colorbars
# Best for: Quick fixes, simple grids

fig.tight_layout()

2. constrained_layout

# 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

# 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

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

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

# For new projects, prefer constrained_layout
fig, axes = plt.subplots(2, 2, constrained_layout=True)