matplotlib
python
plotting
tight_layout
suptitle

tight_layout doesn't take into account figure suptitle

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

In Matplotlib, tight_layout() often improves subplot spacing, but it does not reliably reserve room for a figure-level suptitle. The result is a title that overlaps the top row of plots or gets clipped when you save the figure. The fix is usually to either use the newer constrained layout engine or manually leave room above the subplots.

Why tight_layout() Misses the Figure Title

tight_layout() is mainly concerned with spacing subplot elements such as axis labels, tick labels, and subplot titles. A figure-level title created by fig.suptitle() sits above that normal subplot layout.

This is why code like this often overlaps:

python
1import matplotlib.pyplot as plt
2import numpy as np
3
4fig, axes = plt.subplots(2, 2, figsize=(8, 6))
5fig.suptitle("Main Title", fontsize=16)
6
7for ax in axes.flat:
8    ax.plot(np.random.randn(50))
9    ax.set_title("Subplot Title")
10    ax.set_xlabel("X label")
11    ax.set_ylabel("Y label")
12
13fig.tight_layout()
14plt.show()

The figure title is added, but tight_layout() does not leave enough vertical space for it.

Best Modern Fix: Use constrained_layout

For many new figures, the easiest fix is to use constrained_layout=True when creating the figure:

python
1import matplotlib.pyplot as plt
2import numpy as np
3
4fig, axes = plt.subplots(2, 2, figsize=(8, 6), constrained_layout=True)
5fig.suptitle("Main Title", fontsize=16)
6
7for ax in axes.flat:
8    ax.plot(np.random.randn(50))
9    ax.set_title("Subplot Title")
10    ax.set_xlabel("X label")
11
12plt.show()

This layout engine is better at accounting for figure-level elements such as a suptitle, legends, and colorbars.

If you use constrained_layout, do not also call tight_layout() afterward. They are different layout systems and usually should not be mixed.

Keep tight_layout() but Reserve Space with rect

If you need to stay with tight_layout(), reserve space explicitly with the rect argument:

python
1import matplotlib.pyplot as plt
2import numpy as np
3
4fig, axes = plt.subplots(2, 2, figsize=(8, 6))
5fig.suptitle("Main Title", fontsize=16)
6
7for ax in axes.flat:
8    ax.plot(np.random.randn(50))
9    ax.set_title("Subplot Title")
10
11fig.tight_layout(rect=[0, 0, 1, 0.95])
12plt.show()

The last number, 0.95, means the layout engine should leave the top 5 percent of the figure free. That space becomes available for the suptitle.

This method is simple and often sufficient for static figures.

Manual Control with subplots_adjust

Another option is to adjust the top margin yourself:

python
1import matplotlib.pyplot as plt
2import numpy as np
3
4fig, axes = plt.subplots(2, 2, figsize=(8, 6))
5fig.suptitle("Main Title", fontsize=16)
6
7for ax in axes.flat:
8    ax.plot(np.random.randn(50))
9
10fig.tight_layout()
11fig.subplots_adjust(top=0.88)
12plt.show()

This is useful when you need direct control over spacing or when one figure has unusual typography that automatic layout does not handle well.

Saving the Figure Can Introduce a Second Problem

Even if the title looks fine on screen, the saved image can clip it if the bounding box is too tight. In those cases, saving with bbox_inches="tight" helps:

python
plt.savefig("figure.png", bbox_inches="tight", dpi=150)

This does not replace proper layout, but it often prevents figure-level text from being clipped in the output file.

Choose One Layout Strategy

A good rule of thumb is:

  • use constrained_layout=True for new work when it behaves well for your figure
  • use tight_layout(rect=...) when you need to stay on the older layout path
  • use subplots_adjust(top=...) when you want manual control

Trying to combine several layout methods at once usually makes the figure harder to reason about.

When Manual Positioning Helps

If needed, you can also move the suptitle itself with the y parameter:

python
fig.suptitle("Main Title", fontsize=16, y=0.99)

This can help for one-off figures, but it is usually a secondary adjustment. The primary fix should be making space in the layout rather than floating the title around until it happens to fit.

Common Pitfalls

One common mistake is calling both constrained_layout=True and tight_layout(). These are separate layout systems and often interfere with each other.

Another mistake is adding the suptitle after layout calculations and expecting the spacing to update automatically. The layout engine can only account for elements it knows about when it runs.

Developers also sometimes rely only on bbox_inches="tight" when saving. That may help with clipping, but it does not solve overlap inside the figure.

Finally, hardcoded rect or top values that work for one font size or subplot grid may not work for another. Recheck spacing if the figure structure changes.

Summary

  • 'tight_layout() does not reliably reserve room for fig.suptitle().'
  • The cleanest modern fix is often constrained_layout=True.
  • If you stay with tight_layout(), use rect or subplots_adjust(top=...) to leave vertical space.
  • 'bbox_inches="tight" can help when saving, but it is not a full layout fix.'
  • Pick one layout strategy and keep it consistent for the figure.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.