我只发现代码可以将中位数放在箱线图中,我尝试了一下。但由于我的箱线图是多个,所以无法获取 x-tick 获取定位器。我如何找到箱线图的小刻度定位器,我已经尝试过了,但仍然无法获取多个箱线图位置的位置。有什么建议可以改进这个图吗?
df = pd.DataFrame([['Apple', 10, 'A'],['Apple', 8, 'B'],['Apple', 10, 'C'], ['Apple', 5, 'A'],['Apple', 7, 'B'],['Apple', 9, 'C'], ['Apple', 3, 'A'],['Apple', 5, 'B'],['Apple', 4, 'C'], ['Orange', 3, 'A'],['Orange', 4, 'B'],['Orange', 6, 'C'], ['Orange', 2, 'A'],['Orange', 8, 'B'],['Orange', 4, 'C'], ['Orange', 8, 'A'],['Orange', 10, 'B'],['Orange', 1, 'C']]) df.columns = ['item', 'score', 'grade'] fig = plt.figure(figsize=(6, 3), dpi=150) ax = sns.boxplot(x='item', y='score', data=df, hue='grade', palette=sns.color_palette('husl')) ax.legend(loc='lower right', bbox_to_anchor=(1.11, 0), ncol=1, fontsize = 'x-small').set_title('') medians = df.groupby(['item','grade'])['score'].median().values median_labels = [str(np.round(s, 2)) for s in medians] pos = range(len(medians)) for tick,label in zip(pos, ax.get_xticklabels()): ax.text(pos[tick], medians[tick], median_labels[tick], horizontalalignment='center', size='xx-small', color='w', weight='semibold', bbox=dict(facecolor='#445A64'))
从你描述的问题来看,您希望在箱线图中显示多个中位数值,并且由于存在多个箱线图(hue 被用来区分不同的类别),你需要找到如何定位到每个箱线图的 x 坐标位置,以便将中位数的标签准确地放置在相应位置。
hue
sns.boxplot()
x
'Apple'
'Orange'
'grade'
ax.get_xticklabels()
你可以使用 ax.patches 来获取每个箱线图的具体位置。sns.boxplot() 生成的每个箱线图是一个 Rectangle 对象,你可以通过 ax.patches 获取到所有箱线图的位置及其宽度,然后计算每个中位数标签的位置。
ax.patches
Rectangle
import pandas as pd import seaborn as sns import matplotlib.pyplot as plt import numpy as np # 创建数据 df = pd.DataFrame([['Apple', 10, 'A'],['Apple', 8, 'B'],['Apple', 10, 'C'], ['Apple', 5, 'A'],['Apple', 7, 'B'],['Apple', 9, 'C'], ['Apple', 3, 'A'],['Apple', 5, 'B'],['Apple', 4, 'C'], ['Orange', 3, 'A'],['Orange', 4, 'B'],['Orange', 6, 'C'], ['Orange', 2, 'A'],['Orange', 8, 'B'],['Orange', 4, 'C'], ['Orange', 8, 'A'],['Orange', 10, 'B'],['Orange', 1, 'C']]) df.columns = ['item', 'score', 'grade'] # 绘制箱线图 fig = plt.figure(figsize=(6, 3), dpi=150) ax = sns.boxplot(x='item', y='score', data=df, hue='grade', palette=sns.color_palette('husl')) ax.legend(loc='lower right', bbox_to_anchor=(1.11, 0), ncol=1, fontsize='x-small').set_title('') # 计算每个分组的中位数 medians = df.groupby(['item', 'grade'])['score'].median().values median_labels = [str(np.round(s, 2)) for s in medians] # 获取所有箱线图的位置 positions = [patch.get_x() + patch.get_width() / 2 for patch in ax.patches] # 为每个箱线图标注中位数 for tick, pos in enumerate(positions): ax.text(pos, medians[tick], median_labels[tick], horizontalalignment='center', size='xx-small', color='w', weight='semibold', bbox=dict(facecolor='#445A64')) plt.show()
使用 ax.patches 来获取每个箱线图的 Rectangle 对象。这些对象有 get_x() 和 get_width() 方法,可以帮助你确定每个箱线图的 x 坐标。我们用 get_x() + get_width() / 2 来得到箱线图的中心位置。
get_x()
get_width()
get_x() + get_width() / 2
为每个箱线图添加中位数标签:
positions
这样,你的箱线图中将正确显示每个子箱线图的中位数,并且这些标签会位于每个箱线图的中心位置。