2

I am trying to do stacked bars plots with symmetric error bars in between the two bars, however, the error bars become hidden by the second instance of go.Bar (Example below).

import plotly.graph_objects as go
x_values = ['A','B','C','D','E']
y1_values = [0.527, 0.519, 0.497, 0.458, 0.445]
y2_values = [0.473, 0.481, 0.503, 0.542, 0.555]
y_errors = [0.05, 0.065, 0.158, 0.07, 0.056]


fig = go.Figure(data=[
    go.Bar(name='NAME1', x=x_values, y=y1_values, error_y=dict(type="data", array=y_errors)),
    go.Bar(name='NAME2', x=x_values, y=y2_values)
])
# Change the bar mode
fig.update_layout(barmode='stack')
fig.show()

stacked barplot with errorbars hidden

I could not find a solution to this in the documentation. Is there a way to alter the order of plot elements to force the error bar to appear?

Derek O
  • 16,770
  • 4
  • 24
  • 43
dasilvan9
  • 25
  • 4

1 Answers1

2

You can get around this by plotting the NAME2 bars first, followed by the NAME1 bars – you would need to set the base of the NAME2 bars to be the y1_values of the NAME1 bars (so that the NAME2 bars start from where the NAME1 bars will be), then set the base of the NAME1 bars to be 0 to ensure they start from y=0.

import plotly.graph_objects as go
x_values = ['A','B','C','D','E']
y1_values = [0.527, 0.519, 0.497, 0.458, 0.445]
y2_values = [0.473, 0.481, 0.503, 0.542, 0.555]
y_errors = [0.05, 0.065, 0.158, 0.07, 0.056]


fig = go.Figure(data=[
    go.Bar(name='NAME2', x=x_values, y=y2_values, base=y1_values),
    go.Bar(name='NAME1', x=x_values, y=y1_values, error_y=dict(type="data", array=y_errors), base=[0]*5)
])

# Change the bar mode
fig.update_layout(barmode='stack')

fig.show()

enter image description here

Derek O
  • 16,770
  • 4
  • 24
  • 43
  • Why is it `base=[0]*5` and how does that work for 3 or more stacks? – hans May 15 '23 at 21:21
  • 1
    @hans actually `base=[0]*5` isn't necessary as the last set of bars to be plotted will start from 0 by default, but I wanted the arguments for go.Bar to be consistent. `base=y1_values` is necessary as we need the NAME2 bars to start from where NAME1 bars leave off. And in the same way, if you have 3 or more bars, you would need to specify the base for every set of bars below that one. so if you had `NAME3` on top of `NAME2` and `NAME1` then you would pass the sum of the y1_values and y2_values to the base argument for NAME3 – Derek O May 16 '23 at 02:00
  • Thanks a lot. I tried `base=y2_values` for `NAME3` `fig = go.Figure(data=[ go.Bar(name='NAME3', x=x_values, y=y3_values, error_y=dict(type="data", array=y1_errors), base=y2_values)` but it does not work correctly? – hans May 16 '23 at 07:19
  • 1
    Just figured I have to write `base=[sum(x) for x in zip(y1_values, y2_values)]` for `NAME3` to make it work - thanks again. – hans May 16 '23 at 08:36
  • 1
    @hans glad to have helped! – Derek O May 16 '23 at 15:26