pythonseabornhuecategorical

Is there a way to use more than one categorical variable for the hue command in seaborn?


I am trying to create a stripplot of my variable of interest, separated by group on the x-axis, and colored according to sex.

Treatment sex variable
Drug male 0.24
Drug male -0.42
Drug male 0.43
Drug male 1.39
Drug male 1.62
Drug female 1.53
Drug female 0.08
Drug female 0.68
Drug female 2.46
Drug female 0.02
Placebo male 1.74
Placebo male -0.90
Placebo male -2.39
Placebo male -0.58
Placebo male -0.95
Placebo female 0.71
Placebo female 1.47
Placebo female -0.62
Placebo female 0.73
Placebo female 0.44

I use the following code to create the plot:

g = sns.stripplot(data = df, x = "treatment", y ="variable", hue = "sex", order = ["Drug","Placebo"],hue_order=["male", "female"], palette=dict(male="#466a6e", female="#76b4ba"), dodge=True)

enter image description here

However, I would like to use the green color shades for the Drug group and gray shades for the placebo group (i.e.: Drug Male = #466a6e, Drug Female = #76b4ba, Placebo Male = #706e6d, Placebo Female = #bfbcba) - is there a way to do that?

The closest I have come is to create a new column which concatenates the "treatment" and "sex" thus creating 4 levels to use for the hue command. Yet, this leaves me with the below plot where the strip plots are not aligned over the x-axis ticks:

df['Treat+Sex'] = df['treatment'] + df['sex']

g = sns.stripplot(data = df, x = "treatment", y = "variable", hue = "Treat+Sex", order=["Drug","Placebo"], hue_order=["Drugmale","Drugfemale","Placebomale", "Placebofemale"], palette=dict(Drugmale="#466a6e", Drugfemale="#76b4ba", Placebomale="#706e6d", Placebofemale="#bfbcba"), dodge=True)

enter image description here

Any help is much appreciated.


Solution

  • As there now are 4 values in the "Treat+Sex" hue column, Seaborn will make space for 4 different dodge positions. The 2 for Drug will be placed at the left of the tick position, and the 2 for Placebo will be placed at the right.

    Here is an alternative approach. You could create the sns.stripplot twice with a subset of the dataframe. Once for the Drug treatment and once for the Placebo treatment, each time with different colors. The order= parameter will make sure everything is plotted on the correct position.

    Note that sns.stripplot returns an ax, as it is an axes-level function. The tuple legend handler can be used to help create a combined legend.

    from matplotlib import pyplot as plt
    from matplotlib.legend_handler import HandlerTuple
    import seaborn as sns
    import pandas as pd
    
    df = pd.read_html('https://stackoverflow.com/questions/72165504')[0]
    
    ax = sns.stripplot(data=df[df["Treatment"] == "Drug"],
                       x="Treatment", y="variable", hue="sex", order=["Drug", "Placebo"],
                       hue_order=["male", "female"], palette=dict(male="#466a6e", female="#76b4ba"), dodge=True)
    sns.stripplot(data=df[df["Treatment"] == "Placebo"],
                  x="Treatment", y="variable", hue="sex", order=["Drug", "Placebo"],
                  hue_order=["male", "female"], palette=dict(male="#706e6d", female="#bfbcba"), dodge=True, ax=ax)
    
    handles, labels = ax.get_legend_handles_labels()
    ax.legend(handles=[tuple(handles[i::2]) for i in range(2)], labels=labels[:2], title='Gender',
              handlelength=3, handler_map={tuple: HandlerTuple(ndivide=None, pad=0.2)})
    
    plt.show()
    

    sns.stripplot with two hue categories