[英]Seaborn: Making barplot by group with asymmetrical custom error bars
我有一个Pandas数据框,有几个组列,如下所示。
gr1 grp2 variables lb m ub
A A1 V1 1.00 1.50 2.5
A A2 V2 1.50 2.50 3.5
B A1 V1 3.50 14.50 30.5
B A2 V2 0.25 0.75 1.0
我试图让一个独立的子barplot为每个变量variables
使用FacetGrid
。 我正在努力建立我需要的最终情节,如下所示。
这就是我到目前为止所拥有的。
g = sns.FacetGrid(df, col="variables", hue="grp1")
g.map(sns.barplot, 'grp2', 'm', order=times)
但不幸的是,这是堆叠我所有的数据点。
我应该如何与Seaborn
一起做这件事?
更新:以下代码在很大程度上完成了我的目标,但目前没有显示yerr
。
g = sns.factorplot(x="Grp2", y="m", hue="Grp1", col="variables", data=df, kind="bar", size=4, aspect=.7, sharey=False)
如何将lb
和ub
作为误差条并入factorplot?
在我们开始之前,让我提一下matplotlib要求错误相对于数据,而不是绝对边界。 因此,我们将通过减去相应的列来修改数据帧以解决该问题。
u = u"""grp1 grp2 variables lb m ub
A A1 V1 1.00 1.50 2.5
A A2 V2 1.50 2.50 3.5
B A1 V1 7.50 14.50 20.5
B A2 V2 0.25 0.75 1.0
A A2 V1 1.00 6.50 8.5
A A1 V2 1.50 3.50 6.5
B A2 V1 3.50 4.50 15.5
B A1 V2 8.25 12.75 13.9"""
import io
import pandas as pd
df = pd.read_csv(io.StringIO(u), delim_whitespace=True)
# errors must be relative to data (not absolute bounds)
df["lb"] = df["m"]-df["lb"]
df["ub"] = df["ub"]-df["m"]
现在有两种解决方案,基本相同。 让我们从一个不使用seaborn的解决方案开始,但是大熊猫绘图包装器(原因将在后面变得清晰)。
Pandas允许使用每列属于或构成一个组的数据框来绘制分组条形图。 因此,采取的步骤
variables
的数量创建多个子图。 groupby
由dateframe variables
grp1
作为列, m
为值。 对两个错误列执行相同操作。 然后代码看起来像:
import io
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv(io.StringIO(u), delim_whitespace=True)
# errors must be relative to data (not absolute bounds)
df["lb"] = df["m"]-df["lb"]
df["ub"] = df["ub"]-df["m"]
def func(x,y,h,lb,ub, **kwargs):
data = kwargs.pop("data")
# from https://stackoverflow.com/a/37139647/4124317
errLo = data.pivot(index=x, columns=h, values=lb)
errHi = data.pivot(index=x, columns=h, values=ub)
err = []
for col in errLo:
err.append([errLo[col].values, errHi[col].values])
err = np.abs(err)
p = data.pivot(index=x, columns=h, values=y)
p.plot(kind='bar',yerr=err,ax=plt.gca(), **kwargs)
fig, axes = plt.subplots(ncols=len(df.variables.unique()))
for ax, (name, group) in zip(axes,df.groupby("variables")):
plt.sca(ax)
func("grp2", "m", "grp1", "lb", "ub", data=group, color=["limegreen", "indigo"])
plt.title(name)
plt.show()
Seaborn factorplot不允许自定义错误栏。 因此,人们需要使用FaceGrid
方法。 为了不将条形图堆叠起来,可以将hue
参数放在map
调用中。 因此,以下等同于来自问题的sns.factorplot
调用。
g = sns.FacetGrid(data=df, col="variables", size=4, aspect=.7 )
g.map(sns.barplot, "grp2", "m", "grp1", order=["A1","A2"] )
现在的问题是,我们无法从外部将错误栏放入条形图中,或者更重要的是,我们无法将分组条形图的错误提供给seaborn.barplot
。 对于非分组的条形图,可以通过yerr
参数提供错误,该参数将传递到matplotlib plt.bar
图。 这个概念在这个问题中显示出来。 然而,由于seaborn.barplot
电话plt.bar
几次,一次为每个hue
,在每个呼叫的错误将是相同的(或它们的尺寸将不匹配)。
我看到的唯一选择是使用FacetGrid
并映射与上面使用的完全相同的函数。 这在某种程度上使得seaborn的使用过时,但为了完整性,这里是FacetGrid
解决方案。
import io
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
df = pd.read_csv(io.StringIO(u), delim_whitespace=True)
# errors must be relative to data (not absolute bounds)
df["lb"] = df["m"]-df["lb"]
df["ub"] = df["ub"]-df["m"]
def func(x,y,h,lb,ub, **kwargs):
data = kwargs.pop("data")
# from https://stackoverflow.com/a/37139647/4124317
errLo = data.pivot(index=x, columns=h, values=lb)
errHi = data.pivot(index=x, columns=h, values=ub)
err = []
for col in errLo:
err.append([errLo[col].values, errHi[col].values])
err = np.abs(err)
p = data.pivot(index=x, columns=h, values=y)
p.plot(kind='bar',yerr=err,ax=plt.gca(), **kwargs)
g = sns.FacetGrid(df, col="variables", size=4, aspect=.7, )
g.map_dataframe(func, "grp2", "m", "grp1", "lb", "ub" , color=["limegreen", "indigo"])
g.add_legend()
plt.show()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.