matplotlib 用不对称的自定义误差条逐组制作海上条形图

hl0ma9xz  于 2023-05-18  发布在  其他
关注(0)|答案(1)|浏览(120)

我有一个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

我试图使用FacetGridvariables中的每个变量分别获得一个子条形图。我试图建立到最后的情节,我需要这看起来像下面。

这是我目前所知道的。

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)

如何将lbub作为误差条纳入因子图中?

2ic8powd

2ic8powd1#

在我们开始之前,让我提一下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绘图 Package 器(稍后会清楚原因)。

未使用Seaborn

Pandas允许通过使用数据框架绘制分组条形图,其中每个列属于或组成一个组。因此,要采取的步骤是
1.根据不同variables的数量创建多个子图。

  1. groupbyvariables
    1.对于每个组,创建一个透视 Dataframe ,该 Dataframe 的值为grp1作为列,值为m。对两个错误列执行同样的操作。
    1.应用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 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

Seaborn factorplot不允许自定义错误条。因此需要使用FaceGrid方法。为了不使条形堆叠,可以在map调用中放入hue参数。因此,以下内容相当于问题中的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图中。这个概念在this question中显示。但是,由于seaborn.barplot多次调用plt.bar,每个hue调用一次,每次调用中的错误都是相同的(或者它们的维度不匹配)。
因此,我看到的唯一选择是使用FacetGrid并将上面使用的函数完全Map到它。这在某种程度上使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()

相关问题