Seaborn:使用不对称的自定义误差条按组制作条形图

Bla*_*ack 3 python plot data-visualization matplotlib seaborn

我有一个 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
Run Code Online (Sandbox Code Playgroud)

我正在尝试为variables使用中的每个变量获得一个单独的子条形图FacetGrid。我正在尝试构建我需要的最终图,如下所示。

使用 FacetGrid 和多个分类变量绘图

这是我到目前为止。

g = sns.FacetGrid(df, col="variables", hue="grp1")
g.map(sns.barplot, 'grp2', 'm', order=times)
Run Code Online (Sandbox Code Playgroud)

但不幸的是,这堆积了我所有的数据点。

我该Seaborn怎么做呢?

更新:以下代码在很大程度上完成了我所追求的但目前不显示yerr.

g = sns.factorplot(x="Grp2", y="m", hue="Grp1", col="variables", data=df, kind="bar", size=4, aspect=.7, sharey=False)
Run Code Online (Sandbox Code Playgroud)

如何将lbub作为误差线合并到因子图上?

Imp*_*est 6

在我们开始之前,让我提一下 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"]
Run Code Online (Sandbox Code Playgroud)

现在有两种解决方案,它们本质上是相同的。让我们从一个不使用 seaborn 而是使用 Pandas 绘图包装器的解决方案开始(原因稍后会变得清楚)。

不使用 Seaborn

Pandas 允许使用数据框绘制分组条形图,其中每一列属于或构成一个组。因此要采取的步骤是

  1. 根据不同的数量创建多个子图variables
  2. groupby 日期范围由 variables
  3. 对于每个组,创建一个透视数据框,其中包含grp1作为列的值和m作为值的值。对两个错误列执行相同操作。
  4. 应用How add asymmetric errorbars to Pandas grouped barplot 中的解决方案

代码如下所示:

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 /sf/answers/2599775321/
    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()
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

使用 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"] )
Run Code Online (Sandbox Code Playgroud)

现在的问题是,我们无法从外部将误差线放入条形图中,或者更重要的是,我们无法将分组条形图的误差提供给seaborn.barplot。对于未分组的条形图yerr,可以通过传递到 matplotlibplt.bar图的参数提供错误。这个概念显示在这个问题中。但是,由于多次seaborn.barplot调用,每次调用plt.bar一次hue,每次调用中的错误都是相同的(或者它们的维度不匹配)。

因此,我看到的唯一选择是使用 aFacetGrid并将与上面使用的完全相同的函数映射到它。这以某种方式使 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 /sf/answers/2599775321/
    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()
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明