pythonplotseabornstripplot

Color markers in stripplot by a different variable than hue


I have made a Seaborn stripplot on top of barplot that has experience group on the axis, grouped by two different conditions (target present or target not present) from a dataframe using the following code:

IZ_colors = ['#E1F3DC','#56B567']

ax1 = sns.barplot(data=IZ_df, x='Group', y='Time in IZ (%)', hue='Condition',
                  order=['Std_Ctrl','ELS_Ctrl','Std_CSDS','ELS_CSDS'], hue_order=['Empty','Aggressor'],
                  palette=IZ_colors)

hatches = ['','//']
# Loop over the bars
for bars, hatch in zip(ax1.containers, hatches):
    # Set a different hatch for each group of bars
    for bar in bars:
        bar.set_hatch(hatch)
        
            
sns.stripplot(data=IZ_df ,x='Group', y='Time in IZ (%)', hue='Condition', dodge=True,
              order=['Std_Ctrl','ELS_Ctrl','Std_CSDS','ELS_CSDS'], hue_order=['Empty','Aggressor'], 
              palette=IZ_colors, marker='o', size=7, edgecolor='#373737', linewidth=1, color='black',)

plt.legend(bbox_to_anchor=(1.35, 0.7))

However, I would like the markers of the stripplot to be colored by sex (not by condition like how they are now), which is another column in the dataframe. I would still like them to be grouped by hue='Condition'. Is this possible?

plot here


Solution

  • You could create two stripplots, one for each sex and draw them as the same spot. The double entries of the legend can be removed via get_legend_handles_labels() and taking a subset of the handles and the labels.

    Here is an example using the titanic dataset:

    import matplotlib.pyplot as plt
    import seaborn as sns
    
    titanic = sns.load_dataset('titanic')
    
    IZ_colors = ['#E1F3DC', '#56B567']
    
    ax1 = sns.barplot(data=titanic, x='class', y='age', hue='alive',
                      order=['First', 'Second', 'Third'], hue_order=['no', 'yes'],
                      palette=IZ_colors)
    
    hatches = ['', '//']
    for bars, hatch in zip(ax1.containers, hatches):
        for bar in bars:
            bar.set_hatch(hatch)
    for sex, color in zip(['male', 'female'], ['orange', 'turquoise']):
        df_per_sex = titanic[titanic['sex'] == sex]
        sns.stripplot(data=df_per_sex, x='class', y='age', hue='alive',
                      order=['First', 'Second', 'Third'], hue_order=['no', 'yes'],
                      dodge=True, palette=[color] * 2,
                      marker='o', size=4, edgecolor='#373737', linewidth=1)
    handles, labels = ax1.get_legend_handles_labels()
    handles = [handles[0], handles[2]] + handles[4:]
    labels = ['Male', 'Female'] + labels[4:]
    ax1.legend(handles, labels, bbox_to_anchor=(1.01, 0.7), loc='upper left')
    plt.tight_layout()
    plt.show()
    

    stripplot with different colors for non-hue column