Seaborn:使用不对称的自定义错误条按组制作条形图
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
我正在尝试使用 FacetGrid
为 variables
中的每个变量获取单独的子条形图。我正在尝试构建我需要的最终图,如下所示。
这是我目前所拥有的。
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
作为误差线合并到因子图上?
在我们开始之前,让我提一下 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 绘图包装器(原因稍后会清楚)。
没有使用 Seaborn
Pandas 允许使用每列属于或构成一个组的数据框来绘制分组条形图。
因此,要采取的步骤是
- 根据不同的数量创建多个子图
variables
。
groupby
日期框架 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
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
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
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()
我有一个 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
我正在尝试使用 FacetGrid
为 variables
中的每个变量获取单独的子条形图。我正在尝试构建我需要的最终图,如下所示。
这是我目前所拥有的。
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
作为误差线合并到因子图上?
在我们开始之前,让我提一下 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 绘图包装器(原因稍后会清楚)。
没有使用 Seaborn
Pandas 允许使用每列属于或构成一个组的数据框来绘制分组条形图。 因此,要采取的步骤是
- 根据不同的数量创建多个子图
variables
。 groupby
日期框架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
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
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
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()