Search code examples
pandasmatplotlibseabornlegendscatter-plot

How to change scatterplot hue legend handles


The scatter plot generated for the piece of code below using seaborn is as follows.

ax = sns.scatterplot(x="Param_1", 
                     y="Param_2", 
                     hue="Process", style='Item', data=df,
                     s=30, legend='full')

Scatter plot

I wanted to get rid of color legends (for process) in circle as circles also denote data for Item 'One'. What would be the best way to present the colors legends for Process without making a discrepancy with shapes used for Item.


Solution

    • Proxy artists can be created with lines or patches, and used as legend handles.
    • Creating custom handles is thoroughly covered in How to manually create a legend. However, those answers don't account for skipping the style markers.
    • Tested in python 3.11.4, pandas 2.1.0, matplotlib 3.7.2, seaborn 0.12.2
    import seaborn as sns
    import matplotlib.pyplot as plt
    import matplotlib.patches as mpatches
    
    fig,(ax1,ax2) = plt.subplots(ncols=2)
    tips = sns.load_dataset("tips")
    
    hue = "day"
    style = "time"
    
    sns.scatterplot(x="total_bill", y="tip", hue=hue, style=style, data=tips, ax=ax1)
    ax1.set_title("Default Legend")
    sns.scatterplot(x="total_bill", y="tip", hue=hue, style=style, data=tips, ax=ax2)
    ax2.set_title("Custom Legend")
    
    handles, labels = ax2.get_legend_handles_labels()
    for i,label in enumerate(labels):
        if label == hue:
            continue
        if label == style:
            break
        handles[i] = mpatches.Patch(color=handles[i].get_fc()[0])
    ax2.legend(handles, labels)
    

    enter image description here


    • This can be accomplished more concisely by getting the label index for each of the unique values for the column passed to the hue parameter, as long as the same column isn't used for both hue and style.
    # get the indices in labels for the values in the column used for hue
    idx = [labels.index(v) for v in tips[hue].unique()]
    
    for i in idx:
        handles[i] = mpatches.Patch(color=handles[i].get_fc()[0])
    
    ax2.legend(handles, labels)