Advanced Legends

A legend is the key that maps each color, line, or marker to what it represents, and Matplotlib lets you place it anywhere, split it into columns, give it custom entries, and even show several at once.

Learn Advanced Legends in our free Matplotlib course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free Matplotlib course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

In this lesson you'll move legends outside the axes with bbox_to_anchor , lay them out in columns, build custom handles with Line2D and Patch , and stack two legends on one chart.

When lines crowd the corners, push the legend outside the plot. The trick is to pair loc with bbox_to_anchor , a point in axes-fraction coordinates where (0, 0) is the bottom-left and (1, 1) is the top-right. loc names which corner of the legend box latches onto that point.

What you'll see: three trig curves filling the full plotting area, with a titled legend box sitting neatly to the right of the axes instead of covering any of the lines.

Use ncol to lay entries out horizontally — perfect for a legend placed above a wide chart. You can also invent entries that match nothing on the plot using proxy artists : build a Line2D or a Patch by hand and pass them as handles .

Calling ax.legend() a second time replaces the first. To keep both, capture the first legend in a variable and re-attach it with ax.add_artist() before creating the second. This lets you group entries — say, one legend for line styles and another for colors.

What you'll see: a "Data" legend in the upper-right naming the two solid series and a separate "Style" legend in the lower-left explaining the dashed line — both visible because add_artist preserved the first.

Replace each ___ to push the legend below the chart in two columns.

The default bounding box ignores artists outside the axes. ✅ Save with bbox_inches='tight' or call fig.tight_layout() first.

A new ax.legend() replaces the old one. ✅ Save the first in a variable and call ax.add_artist(first) before the second legend.

❌ Empty legend / "No artists with labels found"

Nothing has a label . ✅ Pass label= when plotting, or supply handles= explicitly.

Build a legend from three custom Patch handles representing risk levels, placed outside the axes with a title.

Lesson complete — your legends are pro-grade!

You positioned legends outside the axes, split entries into columns, built custom handles with Line2D and Patch, and stacked two legends using add_artist.

🚀 Up next: Inset & Broken Axes — add a zoom-in inset and fake a broken axis to show data across very different ranges.

Practice quiz

Which argument positions a legend outside the axes by a reference point?

  • outside=True
  • bbox_to_anchor
  • offset
  • anchor_box

Answer: bbox_to_anchor. bbox_to_anchor gives a reference point in axes-fraction coordinates for placing the legend.

In ax.legend(loc='center left', bbox_to_anchor=(1, 0.5)), what does loc do?

  • Sets the axes scale
  • Hides part of the legend
  • Names a color
  • Picks which corner of the legend box anchors to the point

Answer: Picks which corner of the legend box anchors to the point. loc selects the legend-box corner that latches onto the bbox_to_anchor point.

Which argument lays legend entries out in multiple columns?

  • ncol
  • columns
  • rows
  • split

Answer: ncol. ncol=3 arranges the entries into three columns.

What is a proxy artist (custom handle) used for?

  • To save the figure faster
  • To clear the axes
  • A legend entry that does not match any plotted line
  • To rotate the legend

Answer: A legend entry that does not match any plotted line. Proxy artists like Line2D or Patch create legend entries without drawing on the axes.

Which import gives you a line-style proxy handle?

  • from matplotlib.axes import Line2D
  • from matplotlib import Line2D
  • from matplotlib.pyplot import Line2D
  • from matplotlib.lines import Line2D

Answer: from matplotlib.lines import Line2D. Line2D lives in matplotlib.lines.

Which import gives you a filled-swatch proxy handle?

  • from matplotlib.lines import Patch
  • from matplotlib.patches import Patch
  • from matplotlib import Patch
  • from matplotlib.legend import Patch

Answer: from matplotlib.patches import Patch. Patch comes from matplotlib.patches and shows a colored swatch.

What happens when you call ax.legend() a second time?

  • It replaces the first legend
  • It merges both into one
  • It raises an error
  • It is ignored

Answer: It replaces the first legend. A second ax.legend() call replaces the first legend by default.

How do you keep both legends visible on one axes?

  • Pass keep=True
  • Call legend twice quickly
  • Capture the first and re-add it with ax.add_artist(first)
  • Use two figures

Answer: Capture the first and re-add it with ax.add_artist(first). Save the first legend and call ax.add_artist(first) before creating the second.

What does a proxy Line2D([], []) require for its data?

  • A full dataset
  • At least three points
  • Random data
  • Empty data, since it only shows a sample

Answer: Empty data, since it only shows a sample. A proxy Line2D needs empty data ([], []) because it only appears in the legend.

When saving a figure with an outside legend, what prevents it being cut off?

  • bbox_inches='tight'
  • dpi=50
  • transparent=True
  • format='svg'

Answer: bbox_inches='tight'. savefig(..., bbox_inches='tight') expands the bounding box to include the outside legend.