Of course! tight_layout() is one of the most useful and frequently used functions in Matplotlib for improving the layout of plots. It automatically adjusts plot parameters to give a tight layout, preventing elements like titles, labels, and tick labels from overlapping.

Let's break it down with clear explanations and examples.
What is the Problem? Why Do We Need tight_layout()?
When you create a plot with Matplotlib, especially one with multiple subplots, elements can easily overlap.
- Long axis labels can run into the title of an adjacent subplot.
- Tick labels can be cut off by the figure's edge.
- A legend placed outside the plot axes might not fit well.
This makes the plot look unprofessional and hard to read. tight_layout() solves this by automatically adjusting the padding between and around subplots.
The Core Function: plt.tight_layout()
The function is part of the pyplot module, so you call it after creating your plot(s) but before showing or saving it.

Syntax:
matplotlib.pyplot.tight_layout(pad=1.08, h_pad=None, w_pad=None, rect=None)
Key Parameters:
pad: (float, default: 1.08) Padding between the figure edge and the edges of subplots, as a fraction of the font size.h_pad,w_pad: (float, default: None) Padding (height/width) between subplots. IfNone, it's calculated usingpad.rect: (tuple, default: None) If specified, this rectangle(left, bottom, right, top)in normalized figure coordinates (0 to 1) will be used as the bounding box for the entire layout. This is useful if you want to leave space for a main title or a colorbar that spans all subplots.
Example 1: The Problem and the Simple Solution
Let's create a plot with overlapping labels to demonstrate the issue.
import matplotlib.pyplot as plt
import numpy as np
# Sample data
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
# Create a figure with two subplots that will overlap
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6))
# Plot on the first subplot
ax1.plot(x, y1, label='Sine Wave')
ax1.set_xlabel('This is a very long X-axis label for the first plot')
ax1.set_ylabel('Sine Value')
ax1.set_title('Sine Wave Plot')
# Plot on the second subplot
ax2.plot(x, y2, 'r-', label='Cosine Wave')
ax2.set_xlabel('This is a very long X-axis label for the second plot')
ax2.set_ylabel('Cosine Value')
ax2.set_title('Cosine Wave Plot')
# Add a legend to the first plot
ax1.legend(loc='upper right')
# The plot will have overlapping labels
plt.show()
Without tight_layout():

Notice how the x-axis label of the top plot is overlapping with the title of the bottom plot.
Now, let's add just one line of code: plt.tight_layout().
import matplotlib.pyplot as plt
import numpy as np
# Sample data
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
# Create a figure with two subplots
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6))
# Plot on the first subplot
ax1.plot(x, y1, label='Sine Wave')
ax1.set_xlabel('This is a very long X-axis label for the first plot')
ax1.set_ylabel('Sine Value')
ax1.set_title('Sine Wave Plot')
# Plot on the second subplot
ax2.plot(x, y2, 'r-', label='Cosine Wave')
ax2.set_xlabel('This is a very long X-axis label for the second plot')
ax2.set_ylabel('Cosine Value')
ax2.set_title('Cosine Wave Plot')
# Add a legend to the first plot
ax1.legend(loc='upper right')
# --- THE MAGIC LINE ---
plt.tight_layout()
plt.show()
With tight_layout():
As you can see, Matplotlib automatically adjusted the vertical spacing between the subplots to make room for the long labels, eliminating the overlap.
Example 2: Working with rect to Add a Main Title
Sometimes you want a title for the entire figure. If you just use fig.suptitle(), it might overlap with the subplots adjusted by tight_layout(). The rect parameter is the perfect solution for this.
import matplotlib.pyplot as plt
import numpy as np
# Sample data
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
# Create a figure with two subplots
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6))
# Plot data
ax1.plot(x, y1)
ax1.set_title('Sine Wave')
ax1.set_ylabel('Value')
ax2.plot(x, y2, 'r-')
ax2.set_title('Cosine Wave')
ax2.set_xlabel('Time (s)')
# Add a main title for the entire figure
fig.suptitle('My Awesome Trigonometric Analysis', fontsize=16)
# Use tight_layout() with the 'rect' parameter
# 'rect' is (left, bottom, right, top) in normalized coordinates.
# We leave a little space at the top for the suptitle.
plt.tight_layout(rect=[0, 0, 1, 0.96]) # Adjust the top value (0.96) as needed
plt.show()
Result:
Here, tight_layout() did its job of spacing the subplots, but it respected the bounding box defined by rect, ensuring the main title suptitle had its own dedicated space at the top.
Important Caveats and Alternatives
While tight_layout() is powerful, it's not perfect. Here are some things to be aware of:
It Doesn't Work Well with Everything
tight_layout() can fail or produce unexpected results if your plot contains elements that it doesn't know how to handle, such as:
- Inset plots (
axes.inset_axes()) - Complex colorbars (especially those created with
make_axes_locatable) - Arrows or other artists that are anchored outside the axes.
It Can Be "Too Aggressive"
Sometimes it might shrink your plots too much to make everything fit. You can control this with the pad parameter.
# Add more padding plt.tight_layout(pad=2.0)
Alternative: constrained_layout
For more complex layouts, especially those with gridspecs or colorbars, constrained_layout is often a better and more robust choice. It's a newer, more powerful layout engine.
You enable it when you create the figure:
fig, axs = plt.subplots(2, 2, figsize=(10, 8), constrained_layout=True)
# Now, just plotting and adding titles will automatically be handled
for i, ax in enumerate(axs.flat):
ax.plot(np.random.rand(10))
ax.set_title(f'Plot {i+1}')
# No need to call plt.tight_layout()!
# It's applied automatically as you add elements.
fig.suptitle('Using constrained_layout', fontsize=16)
plt.show()
Result with constrained_layout:
constrained_layout is generally recommended for new, complex plots as it's more flexible and predictable.
Summary: tight_layout() vs. constrained_layout
| Feature | plt.tight_layout() |
constrained_layout=True |
|---|---|---|
| How to Use | Called as a function after plotting. | Set as a parameter when creating the figure. |
| When to Call | After all plot elements are added. | Automatically manages layout as elements are added. |
| Best For | Simple plots, quick fixes, and backward compatibility. | Complex plots with grids, colorbars, insets, and multiple subplots. |
| Flexibility | Less flexible. Can fail with complex elements. | More flexible and robust. Handles complex layouts better. |
| Performance | Can be slow on very large plots. | Generally more efficient for complex layouts. |
Recommendation:
- For a quick fix on a simple plot, use
plt.tight_layout(). - For any new, complex plot, use
fig, ax = plt.subplots(..., constrained_layout=True). It's the modern, recommended approach.
