How can I label each boxplot in a seaborn plot with the median value?
E.g.
import seaborn as sns
sns.set_style(\"whitegrid\")
tips = sns.load_dataset
Based on ShikjarDua's excellent approach, I created a version which works independent of tick positions. This comes in handy when dealing with grouped data in seaborn (i.e. hue=parameter). Additionally, I added an explicit switch for fliers, which changes the lines per drawn box.
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.patheffects as path_effects
def main():
sns.set_style("whitegrid")
tips = sns.load_dataset("tips")
# optionally disable fliers
showfliers = False
# plot data and create median labels
box_plot = sns.boxplot(x="day", y="total_bill", data=tips,
showfliers=showfliers, hue="sex")
create_median_labels(box_plot.axes, showfliers)
plt.show()
def create_median_labels(ax, has_fliers):
lines = ax.get_lines()
# depending on fliers, toggle between 5 and 6 lines per box
lines_per_box = 5 + int(has_fliers)
# iterate directly over all median lines, with an interval of lines_per_box
# this enables labeling of grouped data without relying on tick positions
for median_line in lines[4:len(lines):lines_per_box]:
# get center of median line
mean_x = sum(median_line._x) / len(median_line._x)
mean_y = sum(median_line._y) / len(median_line._y)
# print text to center coordinates
text = ax.text(mean_x, mean_y, f'{mean_y:.1f}',
ha='center', va='center',
fontweight='bold', size=10, color='white')
# create small black border around white text
# for better readability on multi-colored boxes
text.set_path_effects([
path_effects.Stroke(linewidth=3, foreground='black'),
path_effects.Normal(),
])
if __name__ == '__main__':
main()