Legends form a crucial part of matplotlib plots by mapping visual encodings like colors, shapes, fills back to their meaning. But choosing the right legend placement is critical to create polished, professional plots that communicate insights effectively.
In this comprehensive guide, we‘ll thoroughly explore matplotlib‘s versatile options to customize legend positioning using Python.
Overview of Plot Legends
Well-formatted legends that clearly explain the meaning of visual encodings are vital for interpretable plots. As matplotlib‘s creator John Hunter puts it:
"If the colors, symbols, hatchings don‘t tell the full story, add a legend."
But legends placed thoughtlessly can often overlap and obscure plot elements.
Overlapping legends hide plot details
Hence learning to optimize legend placement is an indispensable skill for plot customization.
Matplotlib‘s default legend positioning uses complex logic to avoid overlaps. But we can explicitly configure legend locations for creative control.
Advantages of Optimal Legend Placement
Carefully positioning legends using matplotlib:
- Prevents obscuring data elements or labels
- Avoids misleading interpretations
- Highlights patterns, trends and contrasts
- Guides viewer attention
- Enhances visual hierarchy
- Improves accessibility
With the techniques discussed here, you‘ll be able create publication-quality figures.
Overview of Legend Positioning Options
Matplotlib offers abundant flexibility to customize legend placement:
1. Location Strings
Easiest option with aliases like ‘upper left‘
, ‘best‘
2. Bounding Box
Fine-tune bounding box extents using bbox_to_anchor
3. Coordinate Values
Pass tuple coordinates (x, y)
between 0 and 1
4. Multiple & Secondary Legends
Add secondary legends for subplots/grouped plots
5. Extra Customization
Control legend title, border, background etc
Let‘s discuss them in detail.
Positioning Legends Using Strings
The simplest way to change matplotlib legend location is using predefined string codes like:
Best location: ‘best‘
Top Right: ‘upper right‘
Top Left: ‘upper left‘
Bottom Left: ‘lower left‘
Bottom Right: ‘lower right‘
For instance, to place the legend on the top left corner:
import matplotlib.pyplot as plt
plt.legend(loc=‘upper left‘)
plt.show()
We passed the string ‘upper left‘
to parameter loc
in legend()
. This avoids overlap with actual data points.
Some valid location strings like ‘right‘
, ‘lower center‘
:
Location String | Legend Position |
‘best‘ |
Default ideal position |
‘upper left‘ |
Top left corner |
‘upper right‘ |
Top right corner |
‘lower left‘ |
Bottom left corner |
‘lower right‘ |
Bottom right corner |
‘center left‘ |
Left of plot center |
‘right‘ |
Right middle of plot |
‘center‘ |
Center of axes |
Pass any of these strings to loc
to align legends to anchor positions.
Granular Control with Coordinate Values
For precise control, we can pass a tuple of (x, y)
coordinates to loc
.
This allows positioning legends anywhere by specifying location as fractional values of the figure width and height.
plt.legend(loc=(x_ratio, y_ratio))
(0,0)
represents lower left corner(1,1)
represents top right corner(0.5, 0.5)
centers the legend
For instance, this places the legend box centered vertically and 3/4th width horizontally.
plt.legend(loc=(0.75, 0.5))
Coordinate values between 0 and 1 position the legend within figure bounds.
This helps fine-tune legend placement based on the final figure dimensions.
Adjusting the Legend Bounding Box
The previous techniques position the legend within axes area. But legends with more entries need more space.
We can set the legend bounding box completely outside the figure area using bbox_to_anchor
.
It controls size and location by specifying bounding box coordinates:
plt.legend(bbox_to_anchor=(x, y, width, height))
x, y
sets lower left corner of the legend boxwidth, height
sets size of enclosed legend
Consider this plot:
group_size = 100
a = np.random.normal(0, 10, size=group_size)
b = np.random.normal(5, 1, size=group_size)
plt.plot(a, label=‘Group 1‘)
plt.plot(b, label=‘Group 2‘)
plt.legend(bbox_to_anchor=(1.3, 1),
loc=‘upper right‘)
plt.show()
Here:
bbox_to_anchor=(1.3, 1)
positions the legend outsideloc=‘upper right‘
right aligns legend
Anything beyond x=1 or y=1 will render outside visible area.
Anchor Points for Precise Positioning
The coordinate system for bbox_to_anchor
is based on axes bounding box:
(0,0)
represents lower left of axes box(1,1)
represents top right of axes box
We can leverage these anchor points for precise alignment.
Secondary & Multiple Legends
For complex plots with subfigures, nested groups or multidimensional data, we may need to attach legends to specific subplot axes.
Matplotlib allows creating secondary legend handles using:
ax = plt.subplot(1,2,1)
line1, = ax.plot([1,2,4])
line2, = ax.plot([1,3,2])
ax.legend([(line1, line2)], [‘Two Lines‘], loc=‘upper left‘)
Here we pass additional Line2D
object handles to legend()
besides the plotted artists.
We can use this technique to create sub-legends for multi-panel figures, grouped plots etc.
Positioning Multiple Legends
For complex plots with colorbars, dimensions etc we can render multiple legend boxes using:
fig = plt.figure()
ax = fig.add_subplot(111)
l1 = ax.legend(loc="upper left")
l2 = ax.legend(loc="center right")
Making dual legends help separately mapping different plot aspects.
Legend Title, Border and Background
Beyond positioning, Matplotlib allows customizing the legend box appearance itself:
ax.legend(title=‘Legend Title‘) # Sets title
ax.legend(fancybox=True) # Enables border
ax.legend(facecolor=‘grey‘) # Change background
Tweaking background color, border and legend title improves aesthetics and clarity.
Handling Overlapping Legends
If there are too many legend entries causing overlap with labels or plot, we can:
- Reduce font sizes
- Shrink the bounding box
- Wrap text into multiple columns
ax.legend(loc=‘upper center‘, bbox_to_anchor=(0.5, -0.2),
ncol=2, prop={‘size‘: 8})
This techniques prevents obscured plot elements due to oversized legends.
Best Practices for Optimal Legends
Here are some key guidelines for ideal legend placement:
Maintain Aspect Ratio
Avoid distorting axis scales since legends are based on figure coordinates
Align to Non-critical Areas
Place legend away from data points or labels
Use Appropriate Brightness
Pick background colors with enough contrast to aid readability
Keep Only Relevant Entries
Display only entries mapped in current view for clarity
Following these practices will enable creating clean, publication-quality visualizations.
Example Case Study
Let‘s apply these techniques to a real-world visualization. Consider the graph below depicting social media usage across device types and age groups:
Social media usage across devices and demographics
Here we need to:
- Show breakdown across device types
- Display trends across age groups
- Avoid obscuring data points or labels
- Highlight patterns through color encoding
After applying optimal legend positioning:
usage_plot.legend(loc=‘upper center‘,
bbox_to_anchor=(0.5,-0.1), ncol=2)
The repositioned legend now effectively maps colors to the mobile vs desktop split while avoiding overlap with data.
Proper legend placement is crucial for such real-world visualizations with layered dimensions.
Alternate Python Plotting Libraries
While matplotlib is the most widely used Python plotting library, some alternatives like seaborn, plotly and altair also provide legend functionality.
In seaborn, legends are automatically enabled without needing explicit calls. But we can configure appearance and position using legend_out
parameter:
sns.regplot(data=df, x="x", y="y",
label="Regression", legend_out=False)
Plotly legends support more advanced interactivity like toggle visibility, click callbacks through objects like Legend()
and layout.legend
.
Altair has a Legend()
chart class allowing legends docked at labels, headers etc.
So if matplotlib legends don‘t suffice advanced use cases, do check out these alternate libraries.
Summary
Customizing legend placement is vital for effective matplotlib plots to aid interpretation. We discussed options like:
- Using predefined location strings
- Passing tuple coordinate values
- Adjusting bounding box extents
- Adding secondary legends
- Handling overflow through multilining
Carefully positioned legends transform matplotlib visualizations to publication grade quality.
I hope you found these techniques useful for placing legends in your next data science project!