Matplotlib Legend – A Helpful Illustrated Guide

Rate this post

You’ve plotted some data in Matplotlib but you don’t know which data shows what? It’s time for a legend!

How to add a legend in Python’s Matplotlib library?

  • Label it with the label keyword argument in your plot method.
  • Before, call plt.legend() your plot will be displayed with a legend.

Here’s the minimal example:

import matplotlib.pyplot as plt

plt.plot([1, 2, 3], [1, 4, 9], label='squares')
plt.plot([1, 2, 3], [1, 8, 27], label='cubes')


In the following video, I’ll lead you through the article, step by step.

Matplotlib Legend - A Helpful Illustrated Guide

Prettier Example

# Import necessary modules
import matplotlib.pyplot as plt
import numpy as np

# Optional: Use seaborn style as it looks nicer than matplotlib's default
import seaborn as sns; sns.set()

# Generate data
vals = np.array([0, 1, 2, 3, 4])

# Plot and label
plt.plot(vals, label='vals')


If you plot and label multiple lines, the legend will contain multiple entries.

plt.plot(vals, label='Linear')
plt.plot(vals**2, label='Squared')
plt.plot(vals**0.5, label='Square Root')


You can combine different types of plot – scatter, line, histogram etc. – but you may have to specify the colors manually if you do.

import random

# Set seed to reproduce results

# Generate random data
x = [random.random() for _ in range(100)]
y = [random.random() for _ in range(100)]

# Scatter plot
plt.scatter(x, y, label='Data')

# Red line plot acting as the 'line of best fit'
plt.plot([0, 1], label='Best Fit', c='r')

In this example, I first generated some random data before making a scatter plot from it. Then, I drew a line plot on top of it to act as the line of best fit (note that this is just an example and isn’t actually the line of best fit for this dataset!). Unfortunately, matplotlib does not automatically change the color of each plot if you plot a line and a scatter plot on top of each other. So, I manually changed it to red with the c keyword argument.

To learn more about Python’s random module, check out my article.

Let’s dive into a more detailed example of how legends work in matplotlib.

Matplotlib Legend Example

To display a legend on any plot, you must call plt.legend() at some point in your code – usually, just before is a good place.

There are 3 ways you can call it:

  1. plt.legend()
  2. plt.legend(labels)
  3. plt.legend(handles, labels)

The first option – plt.legend() – automatically detects which elements to show. It does this by displaying all plots that have been labeled with the label keyword argument. The order of the lines in the legend are the same as the order you plot them.

vals = np.array([0, 1, 2, 3, 4])

# Plot vals first
plt.plot(vals, label='vals')

# Plot vals/2 second
plt.plot(vals/2, label='vals/2')

# Call plt.legend() without arguments

First I plotted vals and then plotted vals/2. You can see that vals is displayed first in the legend and is a blue line. Now let’s swap the order.

# Plot vals/2 first
plt.plot(vals/2, label='vals/2')

# Plot vals second
plt.plot(vals, label='vals')

# Call plt.legend() without arguments

Now vals/2 is displayed first in the legend and is colored blue. By changing the order of the plots, you change not only the order in the legend but also the colors of the lines.

Note: you can manually control the colors using the c keyword argument if you want to.

The second option –plt.legend(labels) – is rarely used but I’ll show you what it does just for completeness.

The argument labels must be an iterable – most likely a list or tuple – containing the labels you want to display in the legend. Instead of explicitly labeling each line you draw like so:

plt.plot(x_1, label='plot_1')
plt.plot(x_2, label='plot_2')

You do not label any of the lines explicitly and instead label them based on the order they appear:

plt.legend(['plot_1', 'plot_2'])

This method does work but can cause you a lot of headaches. For example, the iterable labels must be exactly the same length as the number of lines you draw. Moreover, if you change the order of any of your plots, you must also change the order of the elements in labels. Lastly, it violates The Zen of Python Explicit is better than implicit because you implicitly label each plot based on its order.

It is much easier for everyone if you explicitly label each of the plots rather than implicitly doing so like this. Thus, both the matplotlib docs and I do not recommend you use this method.

The final method – plt.legend(handles, labels) – provides you with the most flexibility but takes slightly longer to write.

Both handles and labels are iterables – usually lists or tuples. The handles are the lines you wish to appear on the legend and the labels are, as I hope you know by now, the word(s) you want to appear in the legend next to each line.

# Save plots with descriptive variable names
linear, = plt.plot(vals)
sqrt, = plt.plot(vals**0.5)

# Create iterables handles and labels
handles = [linear, sqrt]
labels = ['Linear', 'Square Root']

# Pass handles and lables to plt.legend()
plt.legend(handles, labels)

First, you must save the output of each line in a variable. The function plt.plot() returns a list of length 1, so you must unpack it by putting a comma after your variable name to get the value inside the list. The value is a matplotlib.lines.Line2D object which is how matplotlib stores lines.

# linear_wrong is a list of length 1
linear_wrong = plt.plot(val)

# linear_correct is a Line2D object - what you want
linear_correct, = plt.plot(val)

For ease of reading, I created the lists handles and labels which I then passed to plt.legend(). You can skip this intermediate step if you wish.

The biggest advantage of this method is that you have total control of the order in which the legend’s items appear: the order you pass handles is the order they will appear. This means you can plot them in any order you want and still control the order of the legend entries. This is in contract to method 1 where the order you plot your lines is the order they appear in the legend.

So, to make Square Root appear as the first entry in the legend, do the following.

linear, = plt.plot(vals)
sqrt, = plt.plot(vals**0.5)

# Swap order of sqrt and linear
handles_ = [sqrt, linear]
labels_ = ['Square Root', 'Linear']

plt.legend(handles_, labels_)

In this plot, the color of the lines has not changed but the order in the legend has changed because I changed the lists handles and labels.

Finally, one thing many Python programmers don’t know is that if your label starts with an underscore, it will not be displayed in the legend. This may be useful if you have many plots and want to be able to easily scan the code but not display the names in the plots.

# No legend displayed because of underscore
plt.plot(vals, label='_I will not be displayed')
No handles with labels found to put in legend.

Matplotlib Legend Location

To change the location of a legend in matplotlib, use the loc keyword argument in plt.legend().

By default, matplotlib draws the legend in the ‘best’ location i.e. the place that overlaps the least with the lines drawn. This can be slow if you plot a lot of data, so manually setting a location can speed up the process.

To manually set it, use the loc keyword and one of these 10, self-explanatory, strings:

  • ‘upper right’, ‘upper left’, ‘upper center’
  • ‘lower right’, ‘lower left’, ‘lower center’
  • ‘center right’ or ‘center left’
  • ‘right’ or ‘center’ (for some reason, ‘left’ is not an option)

Here are some examples of putting the legend in different locations. If you are unsure how to plot subplots in matplotlib, check out my article.

fig, axes = plt.subplots(nrows=1, ncols=3, figsize=plt.figaspect(1/3))

# Differnet legend locations
locations = ['best', 'upper center', 'lower left']

for ax, loc in zip(axes.flat, locations):
    ax.plot(vals, label='vals')
    ax.set_title(f"Legend loc='{loc}")

    # Set legend location

You can change the default location for all plots by setting plt.rcParams['legend.loc'] to the loc value of your choice.

Finally, you can choose any coordinate points by passing a 2-tuple to loc instead of a string. This will specify the location of the lower-left corner of the legend as a fraction of the axes. So setting loc=(0.5, 0.5) will place the bottom left corner half way along the x-axis and half way along the y-axis.

plt.plot(vals, label='vals')

# Set location of legend
plt.legend(loc=(0.5, 0.5))

plt.title('Legend loc=(0.5, 0.5)')

If you input loc=(2, 2) you get a very stange looking graph because matplotlib places the legend at double the length and double the height of the axes.

plt.plot(vals, label='vals')

# Set location of legend
plt.legend(loc=(2, 2))

plt.title('Legend loc=(2, 2)')

Of course, it is possible to place the legend at any coordinate point you want. Just remember to scale it by the maximum x- and y-axis values (both 4 in this example). So, to place the legend at the coordinate points (2, 3), pass loc=(2/4, 3/4).

plt.plot(vals, label='vals')

# Set location of legend
plt.legend(loc=(2/4, 3/4))

plt.title('Legend at coordiante points (2, 3)')

Matplotlib Legend Font Size

To change the fontsize of a legend, use the fontsize keyword argument. It can take any int or float – the absolute size in points. Try lots of different sizes to get a feel for it.

You can also pass one of several strings:

['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large']

These are all relative to the current default font size. Let’s look at some examples.

fig, axes = plt.subplots(nrows=1, ncols=3, figsize=plt.figaspect(1/3))

# Different font sizes to try
fonts = ['xx-small', 'medium', 'x-large']

for ax, font in zip(axes.flat, fonts):
    ax.plot(vals, label='vals')
    ax.set_title(f"Legend fontsize='{font}'")

    # Set fontsize in legend

Matplotlib Legend Title

To add a title to a legend use the title keyword argument.

plt.plot(vals, label='vals')

# Add title to legend
plt.legend(title='My Awesome Legend')

Matplotlib Legend Title Font Size

To change the font size of the title for a legend in matplotlib use the title_fontsize keyword argument. Like the fontsize keyword argument, it accepts any int or float – the absolute size in points – or one of the fontsize strings.

The matplotlib docs are actually incorrect because they say that title_fontsize only accepts a string or None.

fig, axes = plt.subplots(nrows=1, ncols=3, figsize=plt.figaspect(1/3))

# Differnet fontsizes to try
title_size = ['large', 5, None]

for ax, size in zip(axes.flat, title_size):
    ax.plot(vals, label='vals')
    ax.set_title(f"Legend title_fontsize={size}")

    # Set title_fontsize of the legend
    ax.legend(title='My Awesome Legend', title_fontsize=size)

Matplotlib Legend Color

You can change both the facecolor and edgecolor of a legend using those keyword arguments in the function call.

The facecolor is the main color and the edgecolor is, you guessed it, the color around the edge of the box.

fig, axes = plt.subplots(nrows=2, ncols=2)

# facecolors to choose
colors = ['red', 'blue', 'green', 'yellow']

for ax, color in zip(axes.flat, colors):
    ax.plot(vals, label=color)

    # Set facecolor of the legend

Let’s do the same now but just change the edge color.

fig, axes = plt.subplots(nrows=2, ncols=2)

# Edgecolors to choose
colors = ['red', 'blue', 'green', 'yellow']

for ax, color in zip(axes.flat, colors):
    ax.plot(vals, label=color)

    # Choose edgecolor of legend

Of course, you can mix and match the face and edge colors to your heart’s content.

fig, axes = plt.subplots(nrows=2, ncols=2)

# Colors to use
colors = ['red', 'blue', 'green', 'yellow']

# Same as colors but reversed
edges = colors[::-1]

for ax, color, edge in zip(axes.flat, colors, edges):
    ax.plot([0, 1, 2, 3, 4], label=color)

    # Choose both the facecolor and edgecolor
    ax.legend(facecolor=color, edgecolor=edge)

Matplotlib Legend Order

To learn how to order elements in a legend, check out the Matplotlib Legend Example section.

Matplotlib Legend Background Color

To learn how to change the background color of a legend, check out the Matplotlib Legend Color section.


That’s it, you now know all the basics of working with legends in matplotlib.

You know the three different ways to call the function – plt.legend(), plt.legend(labels) and plt.legend(handles, labels) – you know how to set its location with both strings and coordinate points. Plus you can change the font size, set a title and even change the font size of the title. Lastly, you can jazz up your legends by setting the facecolor or edgecolor to anything you want.

Where To Go From Here?

Do you wish you could be a programmer full-time but don’t know how to start?

Check out the pure value-packed webinar where Chris – creator of – teaches you to become a Python freelancer in 60 days or your money back!

It doesn’t matter if you’re a Python novice or Python pro. If you are not making six figures/year with Python right now, you will learn something from this webinar.

These are proven, no-BS methods that get you results fast.

This webinar won’t be online forever. Click the link below before the seats fill up and learn how to become a Python freelancer, guaranteed.