Home > Back-end >  How to create separate legend sections for colors and markers
How to create separate legend sections for colors and markers

Time:09-23

I would like to plot two features in the same plot. My problem is with the legend. I would like to have one legend for colors(species) and one for the marker (Label defined by me). And I don't need to repeat the colors in the legend, as is happening in this example.

this is what I'm trying:

import seaborn as sns
import matplotlib.pyplot as plt
import random
import matplotlib.colors as mcolors

random.seed(5)
iris = sns.load_dataset("iris")

species_list = list(iris.species.unique())
colors_name = list(mcolors.CSS4_COLORS.keys())
color_species = random.sample(colors_name,len(species_list))


fig,ax = plt.subplots(1,1,figsize=(10,6))

sns.scatterplot(data=iris,edgecolor="black", x=iris.index.values, y='sepal_length',s=50,alpha=0.8, hue='species',palette=color_species,ax=ax,label='Feat. 1')
sns.scatterplot(data=iris,edgecolor="black",marker='*', x=iris.index.values, y='sepal_width',s=90,alpha=0.8, hue='species',palette=color_species,ax=ax, label='Feat. 2')
ax.legend(loc='upper right',bbox_to_anchor=(1.5,1))

ax.set_xlabel('Sample')
ax.set_ylabel('Feature 1 and 2')

enter image description here

CodePudding user response:

  • This is more easily done by reshaping the dataframe into a long form with enter image description here

    import matplotlib.pyplot as plt
    
    # create a matplotlib figure
    fig, ax = plt.subplots(1, 1, figsize=(10, 6))
    
    # create an axes-level plot
    sns.scatterplot(data=im, x='Sample', y='Value', hue='Species', style='Feature', ax=ax)
    ax.spines[['top', 'right']].set_visible(False)
    sns.move_legend(ax, bbox_to_anchor=(1, 0.5), loc='center left', frameon=False)
    

    enter image description here

    CodePudding user response:

    To manipulate the legend, you need to get the legend handles using get_legend_handles_labels(), then pick half the entries (3 in your case) and plot them as a legend. Then use matplotlib.lines to create the kind of icon you need (color, shape, etc.) and pass that as the handles for second legend along with the label text you want. You can use title to add titles to the legends. The code is shown below. Hope this is what you are looking for.

    import seaborn as sns
    import matplotlib.pyplot as plt
    import random
    import matplotlib.colors as mcolors
    
    random.seed(5)
    iris = sns.load_dataset("iris")
    
    species_list = list(iris.species.unique())
    colors_name = list(mcolors.CSS4_COLORS.keys())
    color_species = random.sample(colors_name,len(species_list))
    
    fig,ax = plt.subplots(1,1,figsize=(10,6))
    
    sns.scatterplot(data=iris,edgecolor="black", x=iris.index.values, y='sepal_length',s=50,alpha=0.8, hue='species',
                    palette=color_species,ax=ax)#,label='Feat. 1')
    sns.scatterplot(data=iris,edgecolor="black",marker='*', x=iris.index.values, y='sepal_width',s=90,alpha=0.8, 
                    hue='species',palette=color_species,ax=ax)#, label='Feat. 2')
    
    h,l = ax.get_legend_handles_labels() ##Get the legend handles and lables
    l1 = ax.legend(h[:int(len(h)/2)],l[:int(len(l)/2)], loc='upper right',bbox_to_anchor=(1.2,1), title='Title 1') ##Plot half as the first legend
    
    from matplotlib.lines import Line2D
    myHandle = [Line2D([], [], marker='.', color='red', markersize=10, linestyle='None'),
              Line2D([], [], marker='*', color='blue', markersize=10, linestyle='None')] ##Create custom handles for 2nd legend
    
    l2 = ax.legend(handles=myHandle, labels = ['MyLabel1', 'MyLabel2'], loc='upper right',bbox_to_anchor=(1.2,0.8), title='Title 2') ##Add 2nd legend
    ax.add_artist(l1) # 2nd legend will erases the first, so need to add it
    
    ax.set_xlabel('Sample')
    ax.set_ylabel('Feature 1 and 2')
    

    enter image description here

  • Related