Python

Moving matplotlib legend outside of the axis makes it cutoff by the figure box

25 September 2026 · 6 min read

Moving matplotlib legend outside of the axis makes it cutoff by the figure box

Wrangling legends in Matplotlib can be a frustrating experience, especially when they stubbornly refuse to cooperate and end up partially hidden outside the figure’s boundaries. This seemingly simple task can quickly become a headache, disrupting the visual flow and clarity of your carefully crafted plots. You’ve meticulously tweaked your data visualization, perfected the axes, and chosen just the right color palette, only to find your legend cruelly truncated. Don’t worry, you’re not alone. This issue plagues many data visualization enthusiasts, but thankfully, there are several effective solutions to reclaim control over your legends and achieve presentation-worthy plots. This post will explore the common causes of this problem and provide practical, step-by-step solutions to position your Matplotlib legends precisely where you want them.

Understanding the Legend Confinement Issue

The root of the problem often lies in the interplay between the figure, the axes, and the legend. When a legend is placed outside the axes using parameters like bbox_to_anchor, it’s essentially positioned relative to the axes’ boundaries. However, the figure’s boundaries act as a hard limit, clipping anything that extends beyond them. This is why a legend positioned too far outside the axes gets cut off.

Another contributing factor is the tight layout setting, which attempts to optimize spacing between plot elements. While generally helpful, it can exacerbate the clipping issue with external legends by not accounting for the legend’s full size.

Finally, the size of the figure itself plays a role. A smaller figure size provides less space for external elements like legends, increasing the likelihood of clipping.

Strategies for External Legend Placement

Several techniques allow for precise legend placement outside the plot area. Let’s delve into the most effective ones:

Using bbox_to_anchor and bbox_transform

The bbox_to_anchor parameter specifies the legend’s position. Combining it with bbox_transform allows control over the coordinate system used for positioning. For instance, using fig.transFigure positions the legend relative to the figure’s boundaries, preventing clipping:

import matplotlib.pyplot as plt fig, ax = plt.subplots() ... plot data ... legend = ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0., bbox_transform=fig.transFigure) plt.show() 

Adjusting Figure Size

Sometimes, simply enlarging the figure provides enough space for the legend. Use figsize when creating the figure:

fig, ax = plt.subplots(figsize=(10, 6)) 

Subplots_adjust

The subplots_adjust function allows fine-tuning the spacing around subplots. Increasing the right parameter creates more space on the right side for the legend:

plt.subplots_adjust(right=0.8) 

Advanced Techniques: Constrained Layout and GridSpec

For more complex layouts, consider using constrained_layout=True in plt.subplots(). This automatically adjusts subplot parameters to prevent overlapping elements. Alternatively, GridSpec provides granular control over subplot placement and sizing, allowing for dedicated space for the legend.

For example, when dealing with multiple subplots, GridSpec offers a powerful way to reserve space specifically for the legend, ensuring it doesn’t encroach on the plotted data. This provides a clean and organized layout, even for intricate visualizations.

Practical Examples and Case Studies

Imagine visualizing sales data for different product categories. Placing the legend outside the plot area can enhance readability, especially with numerous categories. By using the bbox_to_anchor and fig.transFigure techniques, you can ensure the legend is fully visible and doesn’t obscure the sales trends.

Another example is plotting scientific data with multiple datasets. A clear, unclipped legend is crucial for interpreting the results. Using subplots_adjust or constrained_layout can prevent legend overlap, ensuring all labels are visible.

[Infographic Placeholder: Illustrating different legend placement techniques and their effect on the plot layout]

  • Always consider the figure size and adjust it as needed.
  • Experiment with bbox_to_anchor, bbox_transform, and subplots_adjust to find the optimal configuration.
  1. Create your plot and legend.
  2. Set the bbox_to_anchor parameter.
  3. Use bbox_transform=fig.transFigure for figure-relative positioning.

Learn more about advanced plotting techniques.For more in-depth information, refer to these resources:

Frequently Asked Questions

Q: Why is my legend still being cut off even with bbox_to_anchor?

A: Ensure you are using bbox_transform=fig.transFigure and have adjusted the figure size appropriately. Tight layout might also interfere; try disabling it.

Effectively positioning legends outside the plot area in Matplotlib requires understanding the interplay between the figure, axes, and legend. By strategically using tools like bbox_to_anchor, bbox_transform, figsize, and subplots_adjust, you can achieve precise legend placement and enhance the visual appeal of your data visualizations. Start experimenting with these techniques and elevate your Matplotlib plots to the next level. Explore advanced layout management with GridSpec and constrained_layout for even greater control. Don’t let rogue legends detract from your data story – take charge and present your visualizations with clarity and precision.

Question & Answer :
I’m familiar with the following questions:

Matplotlib savefig with a legend outside the plot

How to put the legend out of the plot

It seems that the answers in these questions have the luxury of being able to fiddle with the exact shrinking of the axis so that the legend fits.

Shrinking the axes, however, is not an ideal solution because it makes the data smaller making it actually more difficult to interpret; particularly when its complex and there are lots of things going on … hence needing a large legend

The example of a complex legend in the documentation demonstrates the need for this because the legend in their plot actually completely obscures multiple data points.

http://matplotlib.sourceforge.net/users/legend_guide.html#legend-of-complex-plots

What I would like to be able to do is dynamically expand the size of the figure box to accommodate the expanding figure legend.

import matplotlib.pyplot as plt import numpy as np x = np.arange(-2*np.pi, 2*np.pi, 0.1) fig = plt.figure(1) ax = fig.add_subplot(111) ax.plot(x, np.sin(x), label='Sine') ax.plot(x, np.cos(x), label='Cosine') ax.plot(x, np.arctan(x), label='Inverse tan') lgd = ax.legend(loc=9, bbox_to_anchor=(0.5,0)) ax.grid('on') 

Notice how the final label ‘Inverse tan’ is actually outside the figure box (and looks badly cutoff - not publication quality!) enter image description here

Finally, I’ve been told that this is normal behaviour in R and LaTeX, so I’m a little confused why this is so difficult in python… Is there a historical reason? Is Matlab equally poor on this matter?

I have the (only slightly) longer version of this code on pastebin http://pastebin.com/grVjc007

Sorry EMS, but I actually just got another response from the matplotlib mailling list (Thanks goes out to Benjamin Root).

The code I am looking for is adjusting the savefig call to:

fig.savefig('samplefigure', bbox_extra_artists=(lgd,), bbox_inches='tight') #Note that the bbox_extra_artists must be an iterable 

This is apparently similar to calling tight_layout, but instead you allow savefig to consider extra artists in the calculation. This did in fact resize the figure box as desired.

import matplotlib.pyplot as plt import numpy as np plt.gcf().clear() x = np.arange(-2*np.pi, 2*np.pi, 0.1) fig = plt.figure(1) ax = fig.add_subplot(111) ax.plot(x, np.sin(x), label='Sine') ax.plot(x, np.cos(x), label='Cosine') ax.plot(x, np.arctan(x), label='Inverse tan') handles, labels = ax.get_legend_handles_labels() lgd = ax.legend(handles, labels, loc='upper center', bbox_to_anchor=(0.5,-0.1)) text = ax.text(-0.2,1.05, "Aribitrary text", transform=ax.transAxes) ax.set_title("Trigonometry") ax.grid('on') fig.savefig('samplefigure', bbox_extra_artists=(lgd,text), bbox_inches='tight') 

This produces:

[edit] The intent of this question was to completely avoid the use of arbitrary coordinate placements of arbitrary text as was the traditional solution to these problems. Despite this, numerous edits recently have insisted on putting these in, often in ways that led to the code raising an error. I have now fixed the issues and tidied the arbitrary text to show how these are also considered within the bbox_extra_artists algorithm.

[edit] Some of the comments below note that since 2019, the command has been simplified. plt.savefig(‘x.png’, bbox_inches=‘tight’) was sufficient. Thanks for sharing. – mateuszb Jun 27, 2019