基于 ShikjarDua 的方法,我创建了一个独立于刻度位置的版本。这在处理 seaborn 中的分组数据时会派上用场(即 hue=parameter)。此外,我添加了一个“飞行器检测”,它会更改每个绘制框的线条。
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.patheffects as path_effects
def add_median_labels(ax, precision='.1f'):
lines = ax.get_lines()
boxes = [c for c in ax.get_children() if type(c).__name__ == 'PathPatch']
lines_per_box = int(len(lines) / len(boxes))
for median in lines[4:len(lines):lines_per_box]:
x, y = (data.mean() for data in median.get_data())
# choose value depending on horizontal or vertical plot orientation
value = x if (median.get_xdata()[1] - median.get_xdata()[0]) == 0 else y
text = ax.text(x, y, f'{value:{precision}}', ha='center', va='center',
fontweight='bold', color='white')
# create median-colored border around white text for contrast
text.set_path_effects([
path_effects.Stroke(linewidth=3, foreground=median.get_color()),
path_effects.Normal(),
])
sns.set_style("darkgrid")
tips = sns.load_dataset("tips")
fig, axes = plt.subplots(2, 2, figsize=(10, 10))
for i_fly, show_fliers in enumerate([True, False]):
for i_data, data_kwargs in enumerate([{'x': 'day', 'y': 'total_bill'},
{'y': 'day', 'x': 'total_bill'}]):
ax = sns.boxplot(ax=axes[i_fly, i_data], **data_kwargs, data=tips,
showfliers=show_fliers, hue="sex")
add_median_labels(ax)
ax.set_title((
f"{['Fliers', 'No fliers'][i_fly]}, "
f"{['vertical', 'horizontal'][i_data]}"))
plt.show()