问题
I would like to annotate my violin plot with the number of observations in each group. So the question is essentially the same as this one, except:
- python instead of R,
- seaborn instead of ggplot, and
- violin plots instead of boxplots
Lets take this example from Seaborn API documentation:
import seaborn as sns
sns.set_style("whitegrid")
tips = sns.load_dataset("tips")
ax = sns.violinplot(x="day", y="total_bill", data=tips)
I'd like to have n=62, n=19, n=87, and n=76 on top of the violins. Is this doable?
回答1:
In this situation, I like to precompute the annotated values and incorporate them into the categorical axis. In other words, precompute e.g., "Thurs, N = xxx"
That looks like this:
import seaborn as sns
sns.set_style("whitegrid")
ax= (
sns.load_dataset("tips")
.assign(count=lambda df: df['day'].map(df.groupby(by=['day'])['total_bill'].count()))
.assign(grouper=lambda df: df['day'].astype(str) + '\nN = ' + df['count'].astype(str))
.sort_values(by='day')
.pipe((sns.violinplot, 'data'), x="grouper", y="total_bill")
.set(xlabel='Day of the Week', ylabel='Total Bill (USD)')
)
回答2:
You first need to store all values of y positions and x positions (using your dataset for that) in order to use ax.text, then a simple for
loop can write everything in the positions desired:
import seaborn as sns
import matplotlib.pyplot as plt
tips = sns.load_dataset("tips")
ax = sns.violinplot(x="day", y="total_bill", data=tips)
yposlist = tips.groupby(['day'])['total_bill'].median().tolist()
xposlist = range(len(yposlist))
stringlist = ['n = 62','n = 19','n = 87','n = 76']
for i in range(len(stringlist)):
ax.text(xposlist[i], yposlist[i], stringlist[i])
plt.show()
来源:https://stackoverflow.com/questions/46772191/is-it-possible-to-annotate-a-seaborn-violin-plot-with-number-of-observations-in