How to use rectangles in a custom legend

logo of a chart:ScatterPlot

In a previous post, we saw how to customize a legend in Matplotlib.

This post describes how to build customized legends in Matplotlib to include rectangles in the handles. We will go over several examples with reproducible code snippets.

Problem

For various reasons you may want to add a legend with handles that consist of squares or rectangles. For some plots, such as the ones obtained with plt.fill_between() the legend handle is going to be a rectangle by default (see this example).

However, for other types of charts, you will have to build them up from scratch.

Example

Let's see this problem live with a scatterplot:

import palmerpenguins
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
import numpy as np

Load the data:

penguins = palmerpenguins.load_penguins().dropna()

Now we define a bunch of properties for the chart such as the colors and the list of species:

FLIPPER_LENGTH = penguins["flipper_length_mm"].values
BILL_LENGTH = penguins["bill_length_mm"].values

SPECIES = penguins["species"].values
SPECIES_ = np.unique(SPECIES)

COLORS = ["#1B9E77", "#D95F02", "#7570B3"]

The following code is extracted from the mentioned post on custom legends. Let's see what is the default legend we get for a scatterplot

fig, ax = plt.subplots(figsize=(8, 6))
for species, color in zip(SPECIES_, COLORS):
    idxs = np.where(SPECIES == species)
    ax.scatter(
        FLIPPER_LENGTH[idxs], BILL_LENGTH[idxs], label=species,
        s=50, color=color, alpha=0.7
    )
legend = ax.legend()

plt.show()

Here we are, a scatterplot with circles used in the legend. How to use rectangles instead?

Using rectangles in legend

Let's see how we can override this default behavior and use a rectangle instead. The following function is created to make it simpler to replicate the same plot several times.

def scatterplot():
    fig, ax = plt.subplots(figsize=(8, 6))
    for species, color in zip(SPECIES_, COLORS):
        idxs = np.where(SPECIES == species)
        ax.scatter(
            FLIPPER_LENGTH[idxs], BILL_LENGTH[idxs],
            s=50, color=color, alpha=0.7
        )
    return fig, ax

Let's generate the chart and create the handles for the legend. This is as simple as using matplotlib.patches.Patch.

fig, ax = scatterplot()

handles = [
    Patch(facecolor=color, label=label) 
    for label, color in zip(SPECIES_, COLORS)
]

ax.legend(handles=handles)

plt.show()

Customizing the rectangle

It's also possible to remove the fill and just leave the color of the borders.

fig, ax = scatterplot()

handles = [
    Patch(edgecolor=color, label=label, fill=False) 
    for label, color in zip(SPECIES_, COLORS)
]

ax.legend(handles=handles);

Different colors for fill and border

Or use one color for the fill, and another for the border:

fig, ax = scatterplot()

handles = [
    Patch(facecolor=color, edgecolor="k", label=label) 
    for label, color in zip(SPECIES_, COLORS)
]

ax.legend(handles=handles)

plt.show()

Change shape

And if you want to make them squared, you only need to set both handlelength and handleheight to the same value when creating the legend.

fig, ax = scatterplot()

handles = [
    Patch(facecolor=color, edgecolor="k", label=label, alpha=0.7) 
    for label, color in zip(SPECIES_, COLORS)
]

legend = ax.legend(handles=handles, handlelength=1.4, handleheight=1.4)

plt.show()

Going further

This post explains how to use rectangles in the legend of a chart built with matplotlib.

You might be interested in how to customize your layout and how to customize title.

Contact & Edit


👋 This document is a work by Yan Holtz. You can contribute on github, send me a feedback on twitter or subscribe to the newsletter to know when new examples are published! 🔥

This page is just a jupyter notebook, you can edit it here. Please help me making this website better 🙏!