简体   繁体   中英

Shift error bars in seaborn barplot with two categories?

I am trying to plot some error bars on tope of a seaborn bar plot made with catplot as below. DF output from .to_clipboard(sep=',', index=True) .

Melted DF:

,Parameter,Output,Sobol index,Value
0,$μ_{max}$,P,Total-effect,0.956747485
1,$μ_{max}$,D,Total-effect,-3.08778755e-08
2,$μ_{max}$,I,Total-effect,0.18009523
3,$μ_{max}$,N,Total-effect,0.234568344
4,$μ_{max}$,Mean,Total-effect,0.3428527570305311
5,$m$,P,Total-effect,0.159805431
6,$m$,D,Total-effect,1.13115268
7,$m$,I,Total-effect,0.256635185
8,$m$,N,Total-effect,0.00556940644
9,$m$,Mean,Total-effect,0.38829067561
10,$\alpha_D$,P,Total-effect,0.00115455519
11,$\alpha_D$,D,Total-effect,-0.000953479004
12,$\alpha_D$,I,Total-effect,0.157263821
13,$\alpha_D$,N,Total-effect,0.197434829
14,$\alpha_D$,Mean,Total-effect,0.08872493154649999
15,$N_{max}$,P,Total-effect,0.112155751
16,$N_{max}$,D,Total-effect,0.795253131
17,$N_{max}$,I,Total-effect,0.380872014
18,$N_{max}$,N,Total-effect,0.384059029
19,$N_{max}$,Mean,Total-effect,0.41808498124999993
20,$\gamma_{cell}$,P,Total-effect,0.237220261
21,$\gamma_{cell}$,D,Total-effect,-0.00380320853
22,$\gamma_{cell}$,I,Total-effect,0.00371553068
23,$\gamma_{cell}$,N,Total-effect,0.0010752371
24,$\gamma_{cell}$,Mean,Total-effect,0.059551955062499995
25,$K_d$,P,Total-effect,0.062129271
26,$K_d$,D,Total-effect,-1.46430838e-12
27,$K_d$,I,Total-effect,0.94771372
28,$K_d$,N,Total-effect,0.985790701
29,$K_d$,Mean,Total-effect,0.4989084229996339
30,$μ_{max}$,P,First-order,0.655145193
31,$μ_{max}$,D,First-order,-6.84274992e-20
32,$μ_{max}$,I,First-order,0.00537009868
33,$μ_{max}$,N,First-order,0.000186118183
34,$μ_{max}$,Mean,First-order,0.16517535246575
35,$m$,P,First-order,0.000688037316
36,$m$,D,First-order,0.379773978
37,$m$,I,First-order,0.0065270132
38,$m$,N,First-order,0.00471697043
39,$m$,Mean,First-order,0.0979264997365
40,$\alpha_D$,P,First-order,5.88800317e-07
41,$\alpha_D$,D,First-order,3.59595179e-21
42,$\alpha_D$,I,First-order,0.00405428355
43,$\alpha_D$,N,First-order,4.23811678e-05
44,$\alpha_D$,Mean,First-order,0.00102431337952925
45,$N_{max}$,P,First-order,0.00369586495
46,$N_{max}$,D,First-order,1.71266774e-09
47,$N_{max}$,I,First-order,0.0150083874
48,$N_{max}$,N,First-order,0.00143697969
49,$N_{max}$,Mean,First-order,0.005035308438166935
50,$\gamma_{cell}$,P,First-order,0.0116538163
51,$\gamma_{cell}$,D,First-order,-8.51017704e-24
52,$\gamma_{cell}$,I,First-order,0.00180446631
53,$\gamma_{cell}$,N,First-order,-1.1891221e-07
54,$\gamma_{cell}$,Mean,First-order,0.0033645409244475
55,$K_d$,P,First-order,0.000593392401
56,$K_d$,D,First-order,1.24032496e-17
57,$K_d$,I,First-order,0.314711173
58,$K_d$,N,First-order,0.393636611
59,$K_d$,Mean,First-order,0.17723529410025002

Err DF:

,Parameter,Output,Error,value
0,$μ_{max}$,P,Total Error,0.00532374344
1,$μ_{max}$,D,Total Error,3.27057237e-08
2,$μ_{max}$,I,Total Error,0.00589710262
3,$μ_{max}$,N,Total Error,0.0114684117
4,$μ_{max}$,Mean,Total Error,0.005672322616430925
5,$m$,P,Total Error,0.00043759689
6,$m$,D,Total Error,0.20494168
7,$m$,I,Total Error,0.00562181392
8,$m$,N,Total Error,0.00280516814
9,$m$,Mean,Total Error,0.0534515647375
10,$\alpha_D$,P,Total Error,0.0005054549
11,$\alpha_D$,D,Total Error,0.00103547316
12,$\alpha_D$,I,Total Error,0.00461107762
13,$\alpha_D$,N,Total Error,0.0048878586
14,$\alpha_D$,Mean,Total Error,0.00275996607
15,$N_{max}$,P,Total Error,0.00278612157
16,$N_{max}$,D,Total Error,0.228255264
17,$N_{max}$,I,Total Error,0.0122461237
18,$N_{max}$,N,Total Error,0.00975799636
19,$N_{max}$,Mean,Total Error,0.0632613764075
20,$\gamma_{cell}$,P,Total Error,0.00183489881
21,$\gamma_{cell}$,D,Total Error,0.00380320865
22,$\gamma_{cell}$,I,Total Error,0.000257448243
23,$\gamma_{cell}$,N,Total Error,0.0014860645
24,$\gamma_{cell}$,Mean,Total Error,0.00184540505075
25,$K_d$,P,Total Error,0.00198581744
26,$K_d$,D,Total Error,4.60436562e-12
27,$K_d$,I,Total Error,0.0061495373
28,$K_d$,N,Total Error,0.0104738223
29,$K_d$,Mean,Total Error,0.004652294261151092
30,$μ_{max}$,P,First Error,0.00251411484
31,$μ_{max}$,D,First Error,5.81033819e-20
32,$μ_{max}$,I,First Error,0.000157513959
33,$μ_{max}$,N,First Error,0.000242607282
34,$μ_{max}$,Mean,First Error,0.00072855902025
35,$m$,P,First Error,0.000102871751
36,$m$,D,First Error,0.114462613
37,$m$,I,First Error,0.000544114122
38,$m$,N,First Error,0.00208775169
39,$m$,Mean,First Error,0.029299337640750003
40,$\alpha_D$,P,First Error,2.85055333e-06
41,$\alpha_D$,D,First Error,2.97531464e-21
42,$\alpha_D$,I,First Error,0.000382494131
43,$\alpha_D$,N,First Error,6.18549533e-05
44,$\alpha_D$,Mean,First Error,0.00011179990940750001
45,$N_{max}$,P,First Error,0.000359843541
46,$N_{max}$,D,First Error,1.71266774e-09
47,$N_{max}$,I,First Error,0.00147221438
48,$N_{max}$,N,First Error,0.000931579111
49,$N_{max}$,Mean,First Error,0.000690909686166935
50,$\gamma_{cell}$,P,First Error,0.000245701873
51,$\gamma_{cell}$,D,First Error,9.57051247e-24
52,$\gamma_{cell}$,I,First Error,0.000318847918
53,$\gamma_{cell}$,N,First Error,1.1718385e-07
54,$\gamma_{cell}$,Mean,First Error,0.0001411667437125
55,$K_d$,P,First Error,0.000284942556
56,$K_d$,D,First Error,2.3820604e-18
57,$K_d$,I,First Error,0.00320241658
58,$K_d$,N,First Error,0.00880561072
59,$K_d$,Mean,First Error,0.0030732424640000006

Code:

    # Get dataframes
    df = analysis.sensitivity_analysis_result.get_dataframe(analysis.scenario)
    err_df = df.melt(id_vars=["Parameter", "Output"], value_vars=["Total Error", "First Error"], var_name="Error")
    df = df.melt(id_vars=["Parameter", "Output"], value_vars=["Total-effect", "First-order"], var_name="Sobol index", value_name="Value")

    # Plot
    grid = sns.catplot(data=df, x="Parameter", y="Value", col="Output", col_wrap=2, hue="Sobol index", kind="bar", aspect=1.8, legend_out=False)

    # Add error lines and values
    for ax, var in zip(grid.axes.ravel(), ["P", "D", "I", "N"]):
        # Error bars
        ax.errorbar(x=df[df["Output"] == var]["Parameter"], y=df[df["Output"] == var]["Value"],
                    yerr=err_df[err_df["Output"] == var]["value"], ecolor='black', linewidth=0, capsize=2)

        # Value labels   
        for c in ax.containers:
            if type(c) == matplotlib.container.BarContainer:
                ax.bar_label(c, labels=[f'{v.get_height():.2f}' if v.get_height() >= 0.01 else "<0.01" for v in c], label_type='edge')

    grid.tight_layout()

The issue I'm facing is that the error bar cap sizes are not centered with the actual bar. Here's the output I get. How can I fix this? The x parameter I pass to error bar is not a float but rather a column from a data frame so it is not obvious to me how to shift it.

带有偏心误差线的条形图

You plot categorical values (the x values are strings), the x positions of the (center of the) bar groups and the error bars the way you plotted them are range(n) where n is the number of parameters. These x positions can also be retrieved by ax.xaxis.get_majorticklocs() .

To put the error bars in the middle of the bar you need to consider the offset of each bar relative to the center of the bar group. This offset depends on the bar width (default is 0.8 ) and the number of bars per group. For a generic solution you'll to differentiate between odd and even numbers of bars per group.

The following shows the case for 2 hues or bars per group ( df['Sobol index'].nunique() == 2 ):

# Plot
width = 0.8
grid = sns.catplot(data=df, x="Parameter", y="Value", col="Output", col_wrap=2, hue="Sobol index", kind="bar", aspect=1.8, legend_out=False, width=width)

# Add error lines and values
for ax, var in zip(grid.axes.ravel(), ["P", "D", "I", "N"]):
    # Error bars
    ticklocs = ax.xaxis.get_majorticklocs()
    offset = 0.5 * width / 2  # 2 = number of hues or bars per group
    ax.errorbar(x=np.append(ticklocs - offset, ticklocs + offset), y=df[df["Output"] == var]["Value"],
                yerr=err_df[err_df["Output"] == var]["value"], ecolor='black', linewidth=0, capsize=2, elinewidth=1)

    # Value labels   
    for c in ax.containers:
        if type(c) == matplotlib.container.BarContainer:
            ax.bar_label(c, labels=[f'{v.get_height():.2f}' if v.get_height() >= 0.01 else "<0.01" for v in c], label_type='edge')

grid.tight_layout()

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM