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

479 views Asked by At

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.

1

There are 1 answers

0
JohanC On BEST ANSWER

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