Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Matplotlib Legend: How to Span Across Subplots?

Learn how to make a shared matplotlib legend span multiple subplot areas using constrained layout and axis positioning.
Preview grid of multiple matplotlib subplots with a shared unified legend below all graphs, illustrating before and after legend positioning using fig.legend and constrained layout Preview grid of multiple matplotlib subplots with a shared unified legend below all graphs, illustrating before and after legend positioning using fig.legend and constrained layout
  • 📊 Using a shared legend in Matplotlib makes things clearer and uses subplot space well.
  • 🔍 fig.legend() creates a legend spanning multiple subplots, unlike ax.legend().
  • 🛠️ constrained_layout=True helps avoid overlaps between legends, labels, and titles.
  • 🎯 bbox_to_anchor gives exact control over legend placement outside the plot area.
  • 🧩 Manual legend placement via add_axes lets you adjust it precisely.

Matplotlib is a strong library for making static, interactive, and animated plots in Python. But handling legends in multi-panel plots, also called subplots, can get messy. This article shows you good ways to use a shared legend in Matplotlib subplots. This helps you make neat and clear plots that work well at any size and look professional.

Default Legend Behavior in Subplots

When you make subplots with matplotlib.pyplot.subplots(), each Axes object acts on its own. This includes its legend. If you call ax.legend() on each subplot, you get many separate legends. This happens even if your plots have the same labels.

Example of Default Behavior

import matplotlib.pyplot as plt

fig, axs = plt.subplots(1, 2)

axs[0].plot([1, 2], [3, 4], label='Line A')
axs[0].legend()

axs[1].plot([1, 2], [4, 3], label='Line B')
axs[1].legend()
plt.show()

Each subplot will now have its own legend. As your plots get bigger or more complex, for example in 2×2 grids, a separate legend for each subplot makes them harder to read. And it takes up too much space.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Consequences of Individual Legends

  • Subplot legends might overlap data.
  • Space, up and down or side to side, gets limited.
  • Labels are not consistent if text is repeated.
  • Keeping legends right across many subplots gets hard.

And so, using one legend that covers all subplots is a much better way to go in most multi-panel plots.

Why You Want a Shared Legend

Using a shared legend, especially with similar data or repeated groups, has many upsides:

  • 🚀 Makes it easier to read: People can understand labels from one legend instead of looking at many.
  • 🖼️ Uses plot space well: You get more room for your data.
  • 📐 Shows what is important: It sets aside space for understanding the data, not just showing it.
  • 🔁 Cuts down on repeated info: You have one legend, but it refers to many things.

This is very helpful when working with data grouped by type over time, or with computer models that share settings, or with plots like those on a dashboard.

ax.legend() vs fig.legend()

This is a key difference for making shared legends in Matplotlib:

  • ax.legend(): Puts a legend on a single axes object, meaning one subplot.
  • fig.legend(): Makes a legend for the whole figure. It can bring together labels from many axes.

Example Comparison for Shared Legend

fig, axs = plt.subplots(1, 2)
line1, = axs[0].plot([1, 2], [3, 4], label='Line A')
line2, = axs[1].plot([1, 2], [4, 3], label='Line B')

fig.legend(handles=[line1, line2], loc='upper center', ncol=2)
plt.show()

✅ Result: You get one legend above both subplots. It clearly shows Line A and Line B.

Making Subplots the Right Way

How you set up your subplots matters for how they line up, how they are arranged, and how easy it is to place shared legends.

fig, axs = plt.subplots(2, 2, constrained_layout=True)

for ax in axs.flat:
    ax.plot([1, 2, 3], [1, 4, 9], label='Parabola')

plt.show()

Key Point:

  • Use .flat to go through 2D axes grids in a standard way.
  • Setting constrained_layout=True makes sure labels, axes, and legends do not overlap.

And for many subplots, this method works well and keeps the spacing correct.

Keep Plot Handles and Labels Straight

To use fig.legend() well, you need to say exactly which handles (lines or patches) and labels show up in the legend.

fig, axs = plt.subplots(1, 2)
line1, = axs[0].plot([1, 2, 3], [1, 2, 3], label='Linear')
line2, = axs[1].plot([1, 2, 3], [1, 4, 9], label='Quadratic')

handles = [line1, line2]
labels = [h.get_label() for h in handles]

fig.legend(handles=handles, labels=labels, loc='lower center', bbox_to_anchor=(0.5, -0.05), ncol=2)

💡 Tip:
Hold onto references (like line1, =) so you don't lose the lines you plotted. Using .get_label() is good if you want to get labels with code or change them before you make the legend.

How to Use fig.legend() for Shared Legends

The fig.legend() method is very flexible. It lets you fully control:

  • Where it is on the plot (loc)
  • Its anchor points (bbox_to_anchor)
  • How it looks (for example, the number of columns with ncol)
  • Its style (fontsize, frameon, spacing)

Example: Placing Legend Below All Subplots

fig.legend(handles=handles, loc='lower center', bbox_to_anchor=(0.5, -0.05), ncol=2)
  • bbox_to_anchor=(0.5, -0.05) moves the legend below the plots.
  • ncol=2 puts the legend items in a row.
  • Change these values if you need different spacing.

And use this spot if you like legends at the bottom, like in papers or slide shows.

Adjusting with constrained_layout

The constrained_layout tool in Matplotlib moves subplot positions on its own to stop things from overlapping. It is a good idea to use this when you place shared legends.

fig, axs = plt.subplots(2, 2, constrained_layout=True)
# plotting code...
fig.legend(handles=handles, loc='upper center', ncol=2)
plt.show()

Main Good Points:

  • It changes the space between subplots as needed.
  • It makes sure titles, x/y labels, and legends have enough white space.
  • It also makes sure shared legends, whether above or below, do not cut off or overlap content.

This is important: Always call fig.legend() after you have finished all your plotting. Layout tools need to know everything about the figure to adjust it right.

tight_layout() vs constrained_layout=True

Feature tight_layout() constrained_layout=True
Scope One-time adjustment Moves things as needed, knows the layout
Handles Legends Not well Well
Nesting Subplots Not much Yes
Ease of Use Simple but stiff A bit more complex but strong

Do not use both together unless you have tried each one alone and are sure it does not mess up the layout.

Custom Legend Areas Using add_axes

For very specific plots, or when you need more complex places for your legend, like on busy dashboards or where grids break, you can make another "hidden" axes with add_axes(). Then, put your legend there.

legend_ax = fig.add_axes([0.3, 0.92, 0.4, 0.05])
legend_ax.axis('off')
legend_ax.legend(handles=handles, loc='center', ncol=2)

How the Axes Work Together:

  • [0.3, 0.92, 0.4, 0.05] means [left, bottom, width, height] in figure units, from 0 to 1.
  • This box holds the legend, but you cannot see it because axis('off') is set.

This is the most hands-on, but also the most flexible, way to place legends. It gives you exact control for dashboard-like designs or figures for papers.

How bbox_to_anchor Places Things

The bbox_to_anchor setting works with loc to put a legend anywhere on the plot.

fig.legend(handles=handles, loc='upper center', bbox_to_anchor=(0.5, 1.05), ncol=2)
  • loc='upper center': Sets where it aligns.
  • bbox_to_anchor=(0.5, 1.05): Puts the legend above the figure. This means x is at the center (0.5), and y is just above (1.05).
  • ncol=2: The labels go across, not down.

Try and See Strategy

You often need to move the bbox_to_anchor values a little up or down, or left or right, to find the best spot. Here is a quick guide:

Placement Goal loc bbox_to_anchor
Top center (outside) upper center (0.5, 1.05)
Bottom center (outside) lower center (0.5, -0.05)
Right side (outside) center left (1.02, 0.5)

Fixing Misplaced Legends

Even if you use fig.legend(), legends can sometimes be in the wrong place or hidden. Here is how to fix them:

✅ Checklist for Shared Legend Problems

  • Make sure all subplots are drawn before you call fig.legend() for the legend.
  • Use constrained_layout=True to make text that overlaps adjust on its own.
  • Do not mix tight_layout() unless you really need to.
  • Make the figure bigger if the legend overlaps: fig, axs = plt.subplots(..., figsize=(12, 8)).
  • Put the legend outside plots using bbox_to_anchor in a smart way.
fig.tight_layout()
fig.legend(...)

Sometimes tight_layout() can cause problems with spacing. But if you call the legend after it, it gets the last needed adjustment.

Before/After Comparison

Let us show how much clearer a shared legend makes things.

🔴 Before:

  • Many legends on each subplot
  • Not lined up well, too many labels

✅ After:

  • One legend in the middle, below the whole figure
  • Uses space better
  • Groupings are clear for people looking at the plot

(Pictures or examples could be made in a live notebook)

Summary and Good Ways to Work

Making a shared legend in Matplotlib can greatly improve how plots with many subplots look.

✅ Shared Legend Checklist:

  • Use fig.legend() instead of ax.legend()
  • Get plot handles with line1, = ax.plot(...)
  • Control how the layout looks with constrained_layout=True
  • Put legends in clear spots with bbox_to_anchor
  • Use add_axes() for your own placement if needed

By setting up your figures on purpose and using layout tools, your plots will be easier to understand and look more professional, no matter their size.

Bonus: Style Your Shared Legend

Make your shared legend look better by changing its style:

fig.legend(handles=handles, fontsize='medium', labelspacing=0.5, frameon=True)
  • fontsize='medium': Makes text the same size
  • labelspacing=0.5: Changes the space up and down between legend items
  • frameon=True: Puts a box you can see around the legend

These small changes can help a lot when you show work to others or write papers.

Final Thoughts

Working with a matplotlib legend across subplots means you need to think about layout tools, plot handles, and how you space things. Whether you are making interactive dashboards or static plots for reports, using a shared legend matplotlib method makes sure your data groups are shown clearly and briefly. Getting good at designing subplot legends is a skill that makes your plotting tools better.

And keep looking at Matplotlib to find more layout choices and ways to change things, like grid layouts, colorbars, and notes. Your data should be told in the best way. Give it a plot that fits.


References

Hunter, J. D. (2007). Matplotlib: A 2D graphics environment. Computing in Science & Engineering, 9(3), 90–95. https://doi.org/10.1109/MCSE.2007.55

Waskom, M. L., et al. (2020). Seaborn: Statistical data visualization. Journal of Open Source Software, 5(51), 3021. https://doi.org/10.21105/joss.03021

Van Rossum, G., & Drake, F. (2009). Python 3 Reference Manual. Scotts Valley, CA: CreateSpace.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading