Python
Data Visualization
Matplotlib
Legends
Plotting

matplotlib Legend Markers Only Once

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Matplotlib creates one legend entry per labeled plotting call, which is why repeated series often produce duplicated legend markers. To show each marker only once, either suppress repeated labels while plotting or deduplicate the legend handles after the fact.

Prevent Duplicate Labels While Plotting

The cleanest approach is to assign the real label only the first time a category is plotted. Every later call for the same category can use the reserved label "_nolegend_", which tells Matplotlib to skip that artist when building the legend.

python
1import matplotlib.pyplot as plt
2
3points = [
4    ("A", 1, 2),
5    ("A", 2, 3),
6    ("B", 1, 1),
7    ("B", 2, 2),
8    ("C", 3, 2),
9]
10
11seen = set()
12
13fig, ax = plt.subplots()
14
15for group, x, y in points:
16    label = group if group not in seen else "_nolegend_"
17    seen.add(group)
18    ax.scatter(x, y, label=label, s=100)
19
20ax.legend(title="Group")
21ax.set_xlabel("X")
22ax.set_ylabel("Y")
23ax.set_title("Legend entries appear once")
24plt.show()

This method is efficient because it avoids building duplicate entries in the first place. It is especially useful inside loops where the categories are known as you iterate.

Deduplicate After Plotting

Sometimes you do not control the plotting loop cleanly, or multiple helper functions add labels independently. In that case, build the legend from the axis handles and labels, then keep only the first occurrence of each label.

python
1import matplotlib.pyplot as plt
2
3fig, ax = plt.subplots()
4
5ax.plot([0, 1, 2], [1, 2, 3], marker="o", label="Training")
6ax.plot([0, 1, 2], [1.5, 2.5, 3.5], marker="o", label="Training")
7ax.plot([0, 1, 2], [0.5, 1.5, 2.5], marker="s", label="Validation")
8
9handles, labels = ax.get_legend_handles_labels()
10
11unique = {}
12for handle, label in zip(handles, labels):
13    if label not in unique:
14        unique[label] = handle
15
16ax.legend(unique.values(), unique.keys(), title="Series")
17ax.set_title("Deduplicated legend")
18plt.show()

This pattern is useful when labels come from several code paths. Because Python dictionaries preserve insertion order, the first instance of each label stays in the legend.

Choose The Better Strategy

Both approaches work, but they solve slightly different problems.

Suppress labels during plotting when:

  • You are already plotting in a loop.
  • You want the simplest and cheapest legend creation.
  • You know exactly which series should appear once.

Deduplicate after plotting when:

  • Multiple functions contribute artists.
  • You cannot easily control the original labels.
  • You need to clean up the legend right before display.

It is also common to mix approaches. For example, you may suppress obvious duplicates in the main loop, then still run a final deduplication pass for safety when building a reporting utility.

Marker Styling And Legend Readability

Showing a marker once is only part of the job. A legend should also remain readable when the plot is dense. If many series share similar colors or markers, consider increasing marker size in the legend, moving the legend outside the axes, or adding a title.

For scatter plots, the displayed legend handle is not always identical to the full series on the chart. That is normal. The legend is a compact visual summary, not a second copy of the plot. Focus on keeping labels unique and visually distinct.

If you are using custom artists or collections, get_legend_handles_labels() still works in many cases, but you may need manual handles for heavily customized legends.

Common Pitfalls

The most common mistake is calling ax.legend() repeatedly inside a loop. That rebuilds the legend over and over and often still leaves duplicates behind.

Another problem is giving slightly different text labels to what is conceptually the same series, such as "Training" and "training". Matplotlib treats those as different entries because labels are matched exactly.

Some developers expect label=None to suppress legend creation. In practice, the clearer convention is using "_nolegend_", which Matplotlib explicitly ignores.

Also remember that duplicate legend labels usually indicate duplicate labeled artists. Fixing the legend display does not change the underlying plot objects. If the chart itself is cluttered, you may need to simplify the plotting logic too.

Summary

  • Matplotlib creates legend entries from labeled artists, so repeated labels create duplicates.
  • The simplest fix is to label the first occurrence and use "_nolegend_" for the rest.
  • If plotting is spread across several functions, deduplicate handles and labels before calling legend.
  • Unique labels improve readability more than legend styling alone.
  • Rebuilding the legend in a loop is a common source of clutter and confusion.

Course illustration
Course illustration

All Rights Reserved.