Explain Codes LogoExplain Codes Logo

How do I make a single legend for many subplots?

python
plot-engineering
best-practices
responsive-design
Anton ShumikhinbyAnton Shumikhin·Jan 20, 2025
TLDR

To generate one legend for several subplots, use fig.legend() after gathering plot elements and their labels. Here's a quick example using two subplots (ax1, ax2) in matplotlib:

import matplotlib.pyplot as plt # Create two subplots, plot data with labels fig, (ax1, ax2) = plt.subplots(1, 2) ax1.plot([1, 2, 3], label="Line 1") # "Once upon a time..." ax2.plot([3, 2, 1], label="Line 2") # "In a land far, far away..." # Gather handles and labels, place unified legend handles, labels = zip(*(ax.get_legend_handles_labels() for ax in [ax1, ax2])) fig.legend(handles, labels, loc='center right') # Et voila! plt.show()

This swift script generates a unified legend containing ax1 and ax2 labels and positions it neatly to the right.

Step-by-Step Guide to a Single Legend

Collecting Legend Handles and Labels

Creating a single legend starts with collecting handles and labels from all subplots. You can use a for loop or list comprehension to achieve this. Settle in, gather around, and let's say we've got n subplots:

handles, labels = [], [] for ax in fig.get_axes(): h, l = ax.get_legend_handles_labels() handles.extend(h) labels.extend(l)

The plot thickens, as they say...

Position: Where's the Legend?

In the pyplot realm, you might use:

handles, labels = plt.gca().get_legend_handles_labels()

But fig.legend() is like an ecological Swiss Army Knife, offering you more control. To set your legend outside the plot area like an excited puppy waiting at the door, use bbox_to_anchor and bbox_transform:

fig.legend(handles, labels, loc='upper left', bbox_to_anchor=(1, 1), bbox_transform=plt.gcf().transFigure)

Ensure that your figure size has enough room to prevent the legend from going into hiding or overlapping your insightful plots.

Special Case: Merged Axis Legends

If you're merging axes with the twinx() route, you need to merge the handles and labels like making a delicious plot sandwich:

ax2 = ax1.twinx() # Plot time! handles1, labels1 = ax1.get_legend_handles_labels() handles2, labels2 = ax2.get_legend_handles_labels() handles, labels = handles1 + handles2, labels1 + labels2

Cleaning: Too Much of a Good Thing

After the unified legend is active, remember to remove individual subplot legends. We love legends, but... too much of a good thing, right?

for ax in fig.get_axes(): ax.legend().set_visible(False)

Consistent Visual Style: Dress Code

Be consistent with colors and line styles across subplots. You can set the axes.prop_cycle in plt.rcParams or use the same color and linestyle arguments. It's all about that #PlotAesthetic.

Adding the Legend: Timing Matters

Add your legend after setting your figure size but before fig.tight_layout(). Timing is everything if you don't fancy your legend being cropped like a poorly edited mobile video.

Creating Subplots: Practice Your Plotlines

Never shy away from creating subplots. Flexibility is key:

# Using add_subplot() for dramatic effect for i in range(total_number_of_plots): fig.add_subplot(rows, cols, i + 1)

Once created, position your unified legend outside the plotting loop — we need one legend for the entire movie, not each scene!

Enhance Appearance: Don't Forget the Title

Boost the overall presentation by adding a figure title with fig.suptitle. Using plt.legend() for enhanced positioning (bbox_to_anchor and loc) ensures a plot that's not just beautiful, but informative too.