pythonplotlegendswarmplot

seaborn remove legend in violin plot with swarmplots


I have made a violin plot with swarms like this:

Is it possible to remove just the legend of the swarmplot? It seems the legend has 4 levels, but I just want the first 2 levels.

I tried ax.legend_.remove() but that remove all the legend.

This is the code I use to make the plot:

import seaborn as sns
sns.set(style="whitegrid")
tips = sns.load_dataset("tips")

ax = sns.swarmplot(x="day", y="total_bill", hue = 'smoker', data=tips, color = 'white', dodge=True)
sns.violinplot(x="day", y="total_bill", hue="smoker",data=tips, palette="muted", ax = ax, )

But in the legend, it has four levels, I just hope to remove the legend level for the swarmplot (the black and white dots).


Solution

  • Since I was struggling with the same problem and couldn't find an answer, I decided to provide an answer myself. I am not sure if it's the optimal solution but here we go:

    As you already figured out, the legend is stored in ax.legend_. The legend is simply a matplotlib.legend.Legend object and you can use its handles (ax.legend_.legendHandles) and labels (provided in ax.legend_.texts as a list of matplotlib.text.Text objects) to update the legend. Calling plt.legend(handles, labels) with the handles from the violin plot and the corresponding labels recreates the legend without the swarm plot legend entries. (I switched the order of the two plot invocations to make the code simpler.)

    import matplotlib.pyplot as plt
    import seaborn as sns
    
    sns.set(style="whitegrid")
    tips = sns.load_dataset("tips")
    
    ax = sns.violinplot(
        x="day", y="total_bill", hue="smoker",
        data=tips, palette="muted"
    )
    handles = ax.legend_.legendHandles
    labels = [text.get_text() for text in ax.legend_.texts]
    
    sns.swarmplot(
        x="day", y="total_bill", hue="smoker",
        data=tips, color="white", dodge=True,
        ax=ax    # you can remove this, it will be plotted on the current axis anyway
    )
    
    plt.legend(handles, labels)
    plt.show()