Search code examples
pythonseabornbar-chartfacet-gridstripplot

How to overlay data points on a barplot with a categorical axis


Goal: I am trying to show individual data points in a figure with multiple grouped bar charts using Seaborn.

Problem: I tried to do it with a catplot for the bar chart and another catplot for the individual data points. However, this generates 2 figures: One figure with the bar chart and the other with the individual data points.

Question: Is there a way to show the individual data points in the same figure together with the bar chart using Seaborn?

This is my code generating 2 separate figures:

import seaborn as sns
tips = sns.load_dataset("tips")

g = sns.catplot(
    x="sex", 
    y="total_bill", 
    hue="smoker", 
    row="time", 
    data=tips, 
    kind="bar", 
    ci = "sd", 
    edgecolor="black",
    errcolor="black",
    errwidth=1.5,
    capsize = 0.1,
    height=4, 
    aspect=.7,
)

g = sns.catplot(
    x="sex", 
    y="total_bill", 
    hue="smoker", 
    row="time", 
    data=tips, 
    kind="strip", 
    height=4, 
    aspect=.7,
)

Output:

My output

Question: Is there a way to show the individual data points in the same figure together with the bar chart using Seaborn?


Solution

    • Figure-level plots (seaborn.catplot) may not be combined, however, it's possible to map an axes-level plot (seaborn.stripplot) onto a figure-level plot.
    • palette=sns.color_palette()[:2] ensures the correct colors are used for the overlying markers, and [:2] selects the first two colors, which correspond to the colors use by hue='smoker'.
      • If a custom palette is specified for catplot, use it in .map.
    • Tested in python 3.11.2, matplotlib 3.7.1, seaborn 0.12.2
    import seaborn as sns
    
    tips = sns.load_dataset("tips")
    
    g = sns.catplot(
        x="sex", 
        y="total_bill", 
        hue="smoker", 
        row="time", 
        data=tips, 
        kind="bar", 
        errorbar = "sd", 
        edgecolor="black",
        errcolor="black",
        errwidth=1.5,
        capsize = 0.1,
        height=4, 
        aspect=.7,
        alpha=0.5)
    
    # map data to stripplot
    g.map(sns.stripplot, 'sex', 'total_bill', 'smoker', hue_order=['Yes', 'No'], order=['Male', 'Female'],
          palette=sns.color_palette()[:2], dodge=True, alpha=0.6, ec='k', linewidth=1)
    

    enter image description here