Bird
Raised Fist0
Matplotlibdata~15 mins

Custom legend entries in Matplotlib - Deep Dive

Choose your learning style10 modes available
Overview - Custom legend entries
What is it?
Custom legend entries in matplotlib allow you to create legends that do not directly correspond to plotted data. Instead of automatically using labels from plotted lines or markers, you can define your own legend items with specific symbols and text. This helps make your charts clearer and more informative by highlighting important categories or explanations.
Why it matters
Without custom legend entries, legends only show what is directly plotted, which can be confusing or incomplete. Custom legends let you explain your chart better, especially when you want to add extra information or group data differently. This improves communication and helps others understand your visual story quickly.
Where it fits
Before learning custom legend entries, you should know how to create basic plots and legends in matplotlib. After mastering custom legends, you can explore advanced visualization techniques like interactive plots or combining multiple plot types with clear explanations.
Mental Model
Core Idea
A custom legend entry is a manually created symbol and label that you add to a plot's legend to explain or highlight information not automatically included.
Think of it like...
It's like making your own key for a treasure map, where you draw symbols and write what they mean, instead of just using the map's default markings.
Plot area
┌─────────────────────────────┐
│                             │
│   ●   ○   ▲   ■             │  <-- plotted symbols
│                             │
│ Legend:                     │
│ ┌───────────────┐           │
│ │ ● Apples      │  <-- custom legend entries
│ │ ○ Oranges     │
│ │ ▲ Pears       │
│ │ ■ Unknown     │
│ └───────────────┘           │
└─────────────────────────────┘
Build-Up - 7 Steps
1
FoundationBasic legend creation in matplotlib
🤔
Concept: How to add a simple legend to a plot using labels from plotted data.
import matplotlib.pyplot as plt x = [1, 2, 3] y1 = [2, 3, 4] y2 = [4, 3, 2] plt.plot(x, y1, label='Line 1') plt.plot(x, y2, label='Line 2') plt.legend() plt.show()
Result
A plot with two lines and a legend showing 'Line 1' and 'Line 2' labels.
Understanding how matplotlib automatically uses labels from plotted lines is the foundation for customizing legends later.
2
FoundationUnderstanding legend handles and labels
🤔
Concept: Learn what legend handles and labels are and how matplotlib uses them to build legends.
fig, ax = plt.subplots() line1, = ax.plot([1, 2, 3], [2, 3, 4], label='A') line2, = ax.plot([1, 2, 3], [4, 3, 2], label='B') handles, labels = ax.get_legend_handles_labels() print(handles) print(labels)
Result
Output shows a list of line objects (handles) and their corresponding labels ['A', 'B'].
Knowing that legends are built from handles (symbols) and labels (text) lets you create custom legends by supplying your own.
3
IntermediateCreating custom legend entries manually
🤔Before reading on: do you think you can add a legend entry without plotting a line? Commit to yes or no.
Concept: You can create legend entries by making custom handles and labels without plotting them.
import matplotlib.patches as mpatches red_patch = mpatches.Patch(color='red', label='Red Area') plt.legend(handles=[red_patch]) plt.show()
Result
A legend with a red square and label 'Red Area' appears, even though no red patch is plotted.
Understanding that legend entries can be independent objects allows you to explain parts of your plot not directly drawn.
4
IntermediateUsing Line2D for custom line legend entries
🤔Before reading on: do you think you can create a custom legend entry that looks like a line without plotting it? Commit to yes or no.
Concept: Use matplotlib.lines.Line2D to create custom line symbols for legends.
from matplotlib.lines import Line2D custom_line = Line2D([0], [0], color='green', lw=2, linestyle='--', label='Dashed Green') plt.legend(handles=[custom_line]) plt.show()
Result
A legend shows a green dashed line labeled 'Dashed Green' without any line plotted.
Knowing how to create line-like legend entries helps you represent line styles or categories clearly.
5
IntermediateCombining plotted and custom legend entries
🤔Before reading on: do you think you can mix plotted lines and custom entries in one legend? Commit to yes or no.
Concept: You can combine handles from plotted data and custom handles to build a single legend.
line, = plt.plot([1, 2, 3], [3, 2, 1], label='Plotted Line') from matplotlib.lines import Line2D custom_line = Line2D([0], [0], color='purple', lw=2, linestyle=':', label='Custom Dotted') handles, labels = plt.gca().get_legend_handles_labels() handles.append(custom_line) labels.append('Custom Dotted') plt.legend(handles=handles, labels=labels) plt.show()
Result
Legend shows 'Plotted Line' and 'Custom Dotted' entries together.
Combining handles lets you enrich legends with extra information beyond plotted data.
6
AdvancedCustom legend entries with markers and styles
🤔Before reading on: can you create a legend entry with a custom marker shape and color without plotting it? Commit to yes or no.
Concept: Use Line2D with marker parameters to create custom legend entries with specific markers and styles.
from matplotlib.lines import Line2D custom_marker = Line2D([0], [0], marker='o', color='w', label='Circle Marker', markerfacecolor='orange', markersize=10) plt.legend(handles=[custom_marker]) plt.show()
Result
Legend shows an orange circle marker labeled 'Circle Marker' without any plotted points.
Custom markers in legends help explain symbols used in plots or add new symbolic meaning.
7
ExpertAdvanced control with proxy artists and legend handlers
🤔Before reading on: do you think you can fully customize legend appearance using proxy artists and handlers? Commit to yes or no.
Concept: Proxy artists are dummy objects used to create complex custom legend entries; legend handlers control how these are drawn.
import matplotlib.pyplot as plt from matplotlib.legend_handler import HandlerTuple from matplotlib.lines import Line2D line1 = Line2D([0], [0], color='blue', lw=2) line2 = Line2D([0], [0], color='red', lw=2) plt.legend([(line1, line2)], ['Blue & Red Lines'], handler_map={tuple: HandlerTuple(ndivide=None)}) plt.show()
Result
Legend shows a single entry with both blue and red lines side by side labeled 'Blue & Red Lines'.
Understanding proxy artists and handlers unlocks powerful legend customizations for complex visualizations.
Under the Hood
Matplotlib legends are built from 'handles' and 'labels'. Handles are objects representing symbols (lines, patches, markers). When you call plt.legend(), matplotlib collects handles and labels from plotted objects or those you provide. It then draws the legend box by rendering each handle with its label. Custom legend entries work by creating or supplying handles manually, which matplotlib treats like any plotted object for the legend.
Why designed this way?
This design separates the visual elements (handles) from their descriptions (labels), allowing flexibility. It lets matplotlib automatically generate legends from plots but also lets users override or extend legends with custom entries. This approach balances ease of use with power, avoiding rigid legend generation tied only to plotted data.
Legend Creation Flow
┌───────────────────────────────┐
│ User calls plt.legend()       │
│                               │
│ ↓                             │
│ Collect handles and labels     │
│ - From plotted objects         │
│ - From user-supplied handles   │
│                               │
│ ↓                             │
│ Draw legend box with entries   │
│ - Render each handle symbol    │
│ - Add corresponding label text │
└───────────────────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Do you think legend entries must always match plotted data exactly? Commit yes or no.
Common Belief:Legend entries can only show labels from the data you have plotted.
Tap to reveal reality
Reality:You can create legend entries that do not correspond to any plotted data by making custom handles.
Why it matters:Believing this limits your ability to explain or clarify plots, reducing communication effectiveness.
Quick: Do you think you must plot something visible to create a legend entry? Commit yes or no.
Common Belief:You must plot a visible object to have a legend entry for it.
Tap to reveal reality
Reality:You can create invisible or proxy objects just for legend entries without plotting them.
Why it matters:This misconception prevents adding helpful legend explanations for abstract or combined concepts.
Quick: Do you think legend handles must be lines or patches only? Commit yes or no.
Common Belief:Legend handles can only be lines or patches from matplotlib.
Tap to reveal reality
Reality:Legend handles can be any artist object, including custom proxy artists or tuples of artists.
Why it matters:Knowing this allows advanced legend customization for complex visual storytelling.
Quick: Do you think legend labels must be unique? Commit yes or no.
Common Belief:Legend labels must be unique strings to work properly.
Tap to reveal reality
Reality:Labels can repeat or be the same; matplotlib handles duplicates but this can cause confusion if not managed.
Why it matters:Mismanaging labels can cause unclear legends or unexpected behavior in legend display.
Expert Zone
1
Custom legend entries can use tuples of artists to combine multiple symbols into one legend item, enabling complex explanations.
2
Legend handlers can be customized or subclassed to control exactly how legend entries are drawn, allowing for dynamic or interactive legends.
3
Invisible proxy artists can be used to represent abstract concepts or data groupings that do not have a direct visual representation in the plot.
When NOT to use
Avoid custom legend entries when the automatic legend clearly and simply represents your data. Overusing custom entries can confuse readers. For interactive or dynamic legends, consider using specialized visualization libraries like Plotly or Bokeh instead.
Production Patterns
In production, custom legend entries are used to explain combined data categories, represent missing or special data points, or clarify complex visual encodings. Teams often create reusable legend handle functions to maintain consistent legends across multiple plots.
Connections
Proxy pattern (software design)
Custom legend entries use proxy artists similar to the proxy pattern where a stand-in object represents another.
Understanding proxy objects in software helps grasp how matplotlib uses dummy artists to represent legend items without plotting them.
User interface design
Custom legends improve user interface clarity by providing tailored explanations and reducing cognitive load.
Knowing UI design principles helps create legends that communicate effectively and enhance user understanding.
Cartography (map legends)
Custom legend entries in plots serve the same purpose as map legends, explaining symbols and colors for better interpretation.
Recognizing this connection shows how visualization principles apply across fields to aid comprehension.
Common Pitfalls
#1Creating a legend entry without a proper handle object.
Wrong approach:plt.legend(handles=['Red Area'], labels=['Red Area'])
Correct approach:import matplotlib.patches as mpatches red_patch = mpatches.Patch(color='red', label='Red Area') plt.legend(handles=[red_patch])
Root cause:Passing strings instead of artist objects as handles causes matplotlib to fail drawing the legend symbol.
#2Forgetting to add custom handles to the existing handles list when combining legends.
Wrong approach:line, = plt.plot([1, 2, 3], [3, 2, 1], label='Line') custom_line = Line2D([0], [0], color='green', label='Custom') plt.legend(handles=[custom_line])
Correct approach:handles, labels = plt.gca().get_legend_handles_labels() handles.append(custom_line) labels.append('Custom') plt.legend(handles=handles, labels=labels)
Root cause:Overwriting the legend handles without including existing plotted handles removes original legend entries.
#3Using duplicate labels without managing them.
Wrong approach:plt.plot([1, 2], [3, 4], label='Data') plt.plot([1, 2], [4, 3], label='Data') plt.legend()
Correct approach:plt.plot([1, 2], [3, 4], label='Data 1') plt.plot([1, 2], [4, 3], label='Data 2') plt.legend()
Root cause:Duplicate labels cause confusion in the legend and may lead to unexpected legend behavior.
Key Takeaways
Custom legend entries let you add meaningful explanations to plots beyond what is automatically generated.
Legends are built from handles (symbols) and labels (text), and you can create both manually for full control.
Using proxy artists like Line2D or Patch objects allows you to design any symbol you want in the legend.
Combining plotted and custom handles in one legend enriches your plot's storytelling and clarity.
Advanced techniques like proxy artists and legend handlers enable complex, professional-quality legends.

Practice

(1/5)
1. What is the main purpose of creating custom legend entries in matplotlib?
easy
A. To change the plot background color
B. To increase the plot size
C. To add labels for plot elements that are not automatically labeled
D. To save the plot as an image file

Solution

  1. Step 1: Understand legend purpose

    Legends explain what different plot elements represent.
  2. Step 2: Identify custom legend role

    Custom legend entries add labels for elements not labeled automatically.
  3. Final Answer:

    To add labels for plot elements that are not automatically labeled -> Option C
  4. Quick Check:

    Custom legend entries = add labels [OK]
Hint: Custom legends label unlabeled plot parts quickly [OK]
Common Mistakes:
  • Confusing legend with plot size or color
  • Thinking legend changes plot background
  • Assuming legend saves the plot
2. Which of the following is the correct way to create a custom legend entry for a red line using matplotlib.lines.Line2D?
easy
A. Line2D([0], [0], color='red', label='Red Line')
B. Line2D(color='red', label='Red Line')
C. Line2D([0,1], [0,1], color='red')
D. Line2D([0], [0], 'red', label='Red Line')

Solution

  1. Step 1: Check Line2D constructor

    Line2D requires x and y data points as first two arguments.
  2. Step 2: Verify correct syntax

    Line2D([0], [0], color='red', label='Red Line') uses [0], [0] for points, color='red', and label='Red Line' correctly.
  3. Final Answer:

    Line2D([0], [0], color='red', label='Red Line') -> Option A
  4. Quick Check:

    Line2D needs x,y points + color + label [OK]
Hint: Line2D needs x and y lists first, then style [OK]
Common Mistakes:
  • Omitting x and y data points
  • Passing color as positional argument
  • Missing label parameter
3. What will be the output legend labels for this code snippet?
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D

plt.plot([1, 2, 3], [4, 5, 6], 'b-')
custom_line = Line2D([0], [0], color='red', lw=2)
plt.legend([custom_line], ['Custom Red Line'])
plt.show()
medium
A. A legend with two labels: 'Custom Red Line' and 'blue line'
B. A legend with one label: 'blue line' shown in blue
C. No legend will appear
D. A legend with one label: 'Custom Red Line' shown in red

Solution

  1. Step 1: Analyze plot and legend calls

    Plot draws a blue line but legend uses only custom_line handle with label 'Custom Red Line'.
  2. Step 2: Understand legend content

    Legend shows only what is passed: one red line with label 'Custom Red Line'.
  3. Final Answer:

    A legend with one label: 'Custom Red Line' shown in red -> Option D
  4. Quick Check:

    Legend shows passed handles and labels only [OK]
Hint: Legend shows only handles and labels you pass [OK]
Common Mistakes:
  • Assuming plot lines auto-appear in legend
  • Expecting multiple legend entries without passing handles
  • Thinking legend is empty
4. Identify the error in this code that tries to add a custom legend entry for a green square patch:
import matplotlib.pyplot as plt
from matplotlib.patches import Patch

patch = Patch(color='green', label='Green Square')
plt.legend(handles=patch, labels=['Green Square'])
plt.show()
medium
A. Patch cannot be used for legend entries
B. The 'handles' argument should be a list, not a single Patch object
C. The 'label' parameter is missing in Patch
D. plt.show() must come before plt.legend()

Solution

  1. Step 1: Check handles argument type

    plt.legend expects handles as a list or iterable, not a single object.
  2. Step 2: Identify fix

    Wrap patch in a list: handles=[patch] to fix the error.
  3. Final Answer:

    The 'handles' argument should be a list, not a single Patch object -> Option B
  4. Quick Check:

    Handles must be list or iterable [OK]
Hint: Always pass handles as a list to plt.legend [OK]
Common Mistakes:
  • Passing single object instead of list to handles
  • Ignoring label parameter in Patch
  • Calling plt.show() before plt.legend()
5. You want to create a legend with a blue dashed line labeled 'Trend' and a red circle marker labeled 'Data Point'. Which code correctly creates custom legend entries for this?
hard
A. from matplotlib.lines import Line2D legend_elements = [Line2D([0], [0], color='blue', lw=2, linestyle='--', label='Trend'), Line2D([0], [0], marker='o', color='red', linestyle='', label='Data Point')] plt.legend(handles=legend_elements)
B. from matplotlib.patches import Patch legend_elements = [Patch(color='blue', label='Trend'), Patch(color='red', label='Data Point')] plt.legend(handles=legend_elements)
C. plt.legend(['Trend', 'Data Point'], loc='best')
D. plt.legend(['blue dashed line', 'red circle'])

Solution

  1. Step 1: Identify correct legend handles

    Blue dashed line and red circle marker require Line2D objects with correct styles.
  2. Step 2: Verify code correctness

    from matplotlib.lines import Line2D legend_elements = [Line2D([0], [0], color='blue', lw=2, linestyle='--', label='Trend'), Line2D([0], [0], marker='o', color='red', linestyle='', label='Data Point')] plt.legend(handles=legend_elements) creates Line2D with color='blue', linestyle='--' for 'Trend' and marker='o', color='red' for 'Data Point', then passes handles to plt.legend.
  3. Final Answer:

    from matplotlib.lines import Line2D legend_elements = [Line2D([0], [0], color='blue', lw=2, linestyle='--', label='Trend'), Line2D([0], [0], marker='o', color='red', linestyle='', label='Data Point')] plt.legend(handles=legend_elements) -> Option A
  4. Quick Check:

    Use Line2D with style and marker for custom legend [OK]
Hint: Use Line2D with marker and linestyle for custom legend [OK]
Common Mistakes:
  • Using Patch for line and marker legend
  • Passing only label strings without handles
  • Ignoring linestyle or marker parameters
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard