使用 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")
我正在分析双因子 (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")