使用 matplotlib + pandas 进行多变量双因子设计的箱线图

Boxplots by group for multivariate two-factorial designs using matplotlib + pandas

我正在分析双因子 (M)ANOVA;抽样设计由两个分别具有两个和三个水平的分类变量和一个维度 4 的响应组成。完成 python 中的所有数据解析后,我想继续绘制 python 中的数据. (而不是切换到 R 来绘图。)不过,我的代码不仅非常冗长,而且整个代码看起来和感觉起来都像是一个非常糟糕的 hack。我的问题:生成以下图的 pandas-matplotlib 方式是什么?出于兴趣:我也很高兴看到一个不使用 seaborn 的解决方案。

R中的解决方案(绘图是2行代码):

 # Data managment
 library(reshape2)

 # Plotting
 library(ggplot2)

 # Creating sample data
 set.seed(12345)
 dat = data.frame(matrix(rnorm(42*4, mean=c(10,3,5,1)), ncol=4, byrow=T))
 names(dat) = c('Base', 'State23', 'State42', 'End')
 gen = factor(sample(2, size=42, replace=T), labels=c('WT', 'HET'))
 env = factor(sample(3, size=42, replace=T), labels=c('heavySmoker', 'casualSmoker', 'nonSmoker'))
 dat$genotype = gen
 dat$environment = env

 # Plotting the data
 dam = melt(dat, measure.vars=c('Base', 'State23', 'State42', 'End'))
 p = ggplot(dam, aes(genotype, value, fill=environment)) + geom_boxplot() + facet_wrap(~variable, nrow=1)
 ggsave('boxplot-r.png', plot=p)

这将产生以下情节:

我目前在 python 中的解决方案:

 # Numerics
 import numpy as np
 from numpy.random import randint

 # Data managment
 import pandas as pd
 from pandas import DataFrame
 from pandas import Series

 # Plotting
 import matplotlib
 matplotlib.use('Qt4Agg')
 import matplotlib.pyplot as pt
 import seaborn as sns

 # Creating sample data
 np.random.seed(12345)
 index = pd.Index(np.arange(42))
 frame = DataFrame(np.random.randn(42,4) + np.array([10,3,5,1]), columns=['Base', 'State23', 'State42', 'End'], index=index)
 genotype = Series(['WT', 'HET'], name='genotype', dtype='category')
 environment = Series(['heavySmoker', 'casualSmoker', 'nonSmoker'], name='environment', dtype='category')
 gen = genotype[np.random.randint(2, size=42)]
 env = environment[np.random.randint(3, size=42)]
 gen.index = frame.index
 env.index = frame.index
 frame['genotype'] = gen
 frame['environment'] = env

 # Plotting the data
 response = ['Base', 'State23', 'State42', 'End']
 fig, ax = pt.subplots(1, len(response), sharex=True, sharey=True)
 for i, r in enumerate(response):
     sns.boxplot(data=frame, x='genotype', y=r, hue='environment', ax=ax[i])
     ax[i].set_ylabel('')
     ax[i].set_title(r)

 fig.subplots_adjust(wspace=0)
 fig.savefig('boxplot-python.png')

这将产生以下情节:

正如您可能同意的那样,代码不仅冗长,而且也没有真正满足我的要求。例如,我不知道如何去除图例的多重外观,x轴上的标签是奇数。

编辑 以使用 factorplot 而不是 mwaskom 在评论中建议的 Facetgrid

如果你melt the dataframe, then you can take advantage of Seaborn's factorplot:

df = pd.melt(frame, id_vars=['genotype', 'environment'])

sns.factorplot(data=df, x='genotype', y='value', 
               hue='environment', col='variable', 
               kind='box', legend=True)

您可以在 melt 函数中根据需要重命名 "value" 和 "variable"。

这是生成的图表:


上一个回答FacetGrid

g = sns.FacetGrid(df, col="variable", size=4, aspect=.7)
g.map(sns.boxplot, "genotype", "value", "environment").add_legend(title="environment")