pythonmatplotlibplotboxplotplot-annotations

Adding a legend to a matplotlib boxplot with multiple plots on same axes


I have a boxplot generated with matplotlib:

enter image description here

However, I have no idea how to generate the legend. I get a warning saying:

Legend does not support handles for dict instances.

or

No artists with labels found to put in legend.

I've done a fair bit of searching and there doesn't seem to be an example showing how to achieve this.

bp1 = ax.boxplot(data1, positions=[1,4], notch=True, widths=0.35, patch_artist=True)
bp2 = ax.boxplot(data2, positions=[2,5], notch=True, widths=0.35, patch_artist=True)

ax.legend([bp1, bp2], ['A', 'B'], loc='upper right')

Solution

  • The boxplot returns a dictionary of artists

    result : dict
    A dictionary mapping each component of the boxplot to a list of the matplotlib.lines.Line2D instances created. That dictionary has the following keys (assuming vertical boxplots):

    • boxes: the main body of the boxplot showing the quartiles and the median’s confidence intervals if enabled.
    • [...]

    Using the boxes, you can get the legend artists as

    ax.legend([bp1["boxes"][0], bp2["boxes"][0]], ['A', 'B'], loc='upper right')
    

    Complete example:

    import matplotlib.pyplot as plt
    import numpy as np; np.random.seed(1)
    
    data1=np.random.randn(40,2)
    data2=np.random.randn(30,2)
    
    fig, ax = plt.subplots()
    bp1 = ax.boxplot(data1, positions=[1,4], notch=True, widths=0.35, 
                     patch_artist=True, boxprops=dict(facecolor="C0"))
    bp2 = ax.boxplot(data2, positions=[2,5], notch=True, widths=0.35, 
                     patch_artist=True, boxprops=dict(facecolor="C2"))
    
    ax.legend([bp1["boxes"][0], bp2["boxes"][0]], ['A', 'B'], loc='upper right')
    
    ax.set_xlim(0,6)
    plt.show()
    

    enter image description here