HOWTO · Matplotlib
How to Create a Single Legend for All Subplots in Matplotlib
Learn how to create a single legend for all subplots in Matplotlib with our comprehensive guide. Discover effective methods like using fig.legend(), customizing legend placement, and creating legends from multiple handles. Enhance your data visualizations and improve clarity with these techniques.
On this page
Use fig.legend() to attach one legend to the whole Matplotlib figure. When every subplot shows the same labeled series, reuse the handles and labels from one Axes. When the subplots show different series, collect the handles and labels from each Axes and pass both lists to the figure legend. This differs from ax.legend(), which creates a legend for one Axes.
The examples below use Matplotlib to build the figures. The first also prints the labels collected for its shared legend.
Create a shared figure-level legend when subplots use the same labels
If each subplot plots the same series with the same label, one subplot already provides the entries needed for a shared legend. The example below uses two differently scaled measurements, both labeled measurement. Because the label and meaning match, taking handles from the first Axes is sufficient. Put the legend on fig, rather than calling legend() on each Axes, to show it once for the figure.
Run this example:
import matplotlib
matplotlib.use("Agg")
import logging
# Ignore only Matplotlib's benign cold-start cache notice; other diagnostics
# remain visible on stderr.
class _FontCacheNoticeFilter(logging.Filter):
def filter(self, record):
return "Matplotlib is building the font cache; this may take a moment." not in record.getMessage()
logging.getLogger("matplotlib.font_manager").addFilter(_FontCacheNoticeFilter())
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2, 1, figsize=(6, 4))
x = [0, 1, 2]
for ax, scale in zip(axes, [1, 2]):
ax.plot(x, [scale * value for value in x], label="measurement")
handles, labels = axes[0].get_legend_handles_labels()
fig.legend(handles, labels, loc="upper center")
fig.tight_layout(rect=(0, 0, 1, 0.9))
print("Legend entries:", labels)
plt.show()
Legend entries: ['measurement']
get_legend_handles_labels() returns paired lists for the labeled artists on that Axes. The shared-label approach is concise, but only represents series present on the chosen Axes. If another subplot has a distinct label or series, use the all-Axes approach in the next section.
Collect handles and labels from every Axes when subplot content differs
When different subplots contain different labeled lines, collect each Axes’ handles and labels in the same loop. The lists stay paired by position: a handle at index i corresponds to the label at index i. The code below produces two legend entries, one for each line.
Run this example:
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2, figsize=(7, 3))
axes[0].plot([0, 1, 2], [0, 1, 4], label="quadratic")
axes[1].plot([0, 1, 2], [0, 1, 2], label="linear")
handles, labels = [], []
for ax in axes:
ax_handles, ax_labels = ax.get_legend_handles_labels()
handles.extend(ax_handles)
labels.extend(ax_labels)
fig.legend(handles, labels, loc="upper center", ncol=2)
fig.tight_layout(rect=(0, 0, 1, 0.88))
plt.show()
This collects labeled artists from every Axes, so repeated labels can appear more than once. If the repeated entries refer to the same concept, select one handle for each desired label before calling fig.legend(). Conversely, keep distinct labels when readers need to tell the series apart. For a selected subset, pass only the corresponding handles and labels; the legend does not have to include every plotted line.
Position and format the figure-level legend
The loc argument chooses which point of the legend is aligned with its anchor. For example, fig.legend(..., loc="upper center") centers the legend at the top of the figure. To control the anchor explicitly, use bbox_to_anchor; for a figure legend, its coordinates are relative to the figure. For example, fig.legend(handles, labels, loc="upper center", bbox_to_anchor=(0.5, 1.02)) places the legend just above the top edge. Adjust the anchor values to move it, and reserve space with fig.tight_layout(rect=(0, 0, 1, 0.9)) or fig.subplots_adjust(top=0.82) so it does not cover subplot content.
Legend styling uses the same familiar options as other Matplotlib legends. Pass values such as fontsize=9, frameon=False, or facecolor="white" to fig.legend() to adjust text size, the frame, or its background. When saving a figure with a legend outside its bounds, fig.savefig("plot.png", bbox_inches="tight") can include the outside legend in the saved image.
Common questions about a figure-level legend
What is the difference between ax.legend() and fig.legend()? ax.legend() belongs to a specific Axes. fig.legend() belongs to the Figure and can combine entries supplied from one or more Axes.
How do I make one legend when all subplots use the same labels? Get the handles and labels from one representative Axes, then pass them to fig.legend(). This works when that Axes has the same labeled series as the other subplots.
How do I include only selected lines? Keep the handles and labels you want in paired lists and pass those lists to fig.legend(). For repeated labels, decide whether the entries represent the same series before removing duplicates.
How can I avoid covering the plots? Place the legend in a figure margin with loc and bbox_to_anchor, then reserve room in the subplot layout. If the legend sits outside the canvas, use a tight bounding box when saving so it is not cropped.