我可以使用DataFrameGroupBy.boxplot(...)以下列方式创建一个boxplot:
In [15]: df = pd.DataFrame({"gene_length":[100,100,100,200,200,200,300,300,300],
...: "gene_id":[1,1,1,2,2,2,3,3,3],
...: "density":[0.4,1.1,1.2,1.9,2.0,2.5,2.2,3.0,3.3],
...: "cohort":["USA","EUR","FIJ","USA","EUR","FIJ","USA","EUR","FIJ"]})
In [17]: df.groupby("cohort").boxplot(column="density",by="gene_id")
In [18]: plt.show()
这正是我想要的,除了不是制作三个子图,我希望所有的图都在一个图中(美国,欧元和FIJ的颜色不同)。我试过了
In [17]: df.groupby("cohort").boxplot(column="density",subplots=False,by="gene_id")
但它会产生错误
KeyError: 'gene_id'
我认为问题与by="gene_id"
是发送到matplotlib boxplot方法的关键字这一事实有关。如果有人有更好的方法来制作我想要的情节,可能是使用DataFrame.boxplot(?)代替,请在这里回复。非常感谢!
答案 0 :(得分:2)
要使用纯pandas
函数,我认为您在调用GroupBy
之前不应该boxplot
,而是请求通过调用boxplot
中的某些列进行分组在DataFrame
本身:
df.boxplot(column='density',by=['gene_id','cohort'])
要获得更好看的结果,您可能需要考虑使用Seaborn库。它旨在准确地帮助完成这类任务:
sns.boxplot(data=df,x='gene_id',y='density',hue='cohort')
编辑以考虑以下评论
如果你想为每个gene_id堆叠/叠加你的每个群组箱图,那就更复杂了(加上你可能会得到相当丑陋的输出)。你不能使用Seaborn,AFAIK这样做,但是你可以直接使用pandas,使用position=
参数来设置boxplot(see doc)。捕获它以生成正确的位置序列以将箱形图放置在您想要的位置,但您必须自己修复刻度标签和图例。
pos = [i for i in range(len(df.gene_id.unique())) for _ in range(len(df.cohort.unique()))]
df.boxplot(column='density',by=['gene_id','cohort'],positions=pos)
另一种方法是使用seaborn.swarmplot
而不是使用boxplot。 swarmplot绘制每个点而不是箱形图的合成表示,但是您可以使用参数split=False
来获得由群组着色的点,但是每个gene_id都堆叠在一起。
sns.swarmplot(data=df,x='gene_id',y='density',hue='cohort', split=False)
在不知道数据框的实际内容(每个基因和每个群组的点数,以及它们在每个群组中的分离程度)的情况下,很难说哪种解决方案最合适。