Search code examples
pythonmatplotlibseabornplot-annotationsjointplot

How to add bar value annotations in jointgrid margins


import seaborn as sns

# sample data
planets = sns.load_dataset('planets')

# plot
g = sns.jointplot(data=planets, x='distance', y='orbital_period', color='purple', marginal_ticks=True, marker='.',
                  marginal_kws=dict(bins=10, fill=True, log_scale=True, color='purple', stat='probability'))

g.plot_joint(sns.kdeplot, color='purple', zorder=0, levels=10, fill=True, thresh=0.1)

enter image description here


Solution

    • The margin axes must be used to annotate bars in the jointplot
      • g.ax_marg_x
      • g.ax_marg_y
    • This is only a viable option with one group of bars (because of crowding); not with hue=.
    • The linked answer in the OP has additional details about maptlotlib.pyplot.bar_label, which don't need to be restated here.
    • Tested in python 3.10, matplotlib 3.5.1, seaborn 0.11.2
      • .bar_label is available from matplotlib 3.4.0
      • Assignment expressions (:=) are available from python 3.8
        • [v.get_height().round(3) if v.get_height() > 0 else '' for v in ax_xm.containers[0]] without :=.
    planets = sns.load_dataset('planets')
    
    g = sns.jointplot(data=planets, x='distance', y='orbital_period', color='purple', marginal_ticks=True, marker='.', height=7,
                      marginal_kws=dict(bins=10, fill=True, log_scale=True, color='purple', stat='probability'))
    
    g.plot_joint(sns.kdeplot, color='purple', zorder=0, levels=10, fill=True, thresh=0.1)
    
    # alias for the x margin; this is not necessary, just used for conciseness
    ax_xm = g.ax_marg_x
    
    # only add labels if the value is greater than 0
    xm_labels = [h.round(3) if (h := v.get_height()) > 0 else '' for v in ax_xm.containers[0]]
    
    # annotate the bar
    ax_xm.bar_label(ax_xm.containers[0], labels=xm_labels, label_type='edge', rotation=90, padding=4)
    
    # alias for the y margin
    ax_ym = g.ax_marg_y
    
    # only add labels if the value is greater than 0
    ym_labels = [w.round(3) if (w := v.get_width()) > 0 else '' for v in ax_ym.containers[0]]
    
    # annotate the bar
    _ = ax_ym.bar_label(ax_ym.containers[0], labels=ym_labels, label_type='edge', padding=3)
    

    enter image description here