Search code examples
pythonplotlyrectangles

Filled error bars in Python Plotly


I saw this question to do with matplotlib here:

Filled errorbars in matplotlib (rectangles)

I was wondering if something like this is possible in Plotly?

To be specific, I want to know whether you can take a "Scatter" graph object and fill the error bars with a rectangle, as in the following image:

enter image description here

Thanks in advance!


Solution

  • There is no direct way of doing it but you can just add shapes in your layout.

    Let's assume the errors are a two dimensional list:

    errors = {'x': [[0.1, 0.4],
                    [0.2, 0.3],
                    [0.3, 0.2],
                    [0.4, 0.1],
                    [0.45, 0.05]
                   ],
              'y': [[0.4, 0.1],
                    [0.3, 0.2],
                    [0.2, 0.3],
                    [0.1, 0.4],
                    [0.05, 0.45]]}
    

    Now we create a rectangle shape for each error:

    shapes = list()
    for i in range(len(errors['x'])):
        shapes.append({'x0': points['x'][i] - errors['x'][i][0],
                       'y0': points['y'][i] - errors['y'][i][0],
                       'x1': points['x'][i] + errors['x'][i][1],
                       'y1': points['y'][i] + errors['y'][i][1],
                       'fillcolor': 'rgb(160, 0, 0)',
                       'layer': 'below',
                       'line': {'width': 0}
                      })
    layout = plotly.graph_objs.Layout(shapes=shapes)
    

    enter image description here

    The asymmetric error bars are created via 'symmetric': False

    Complete code

    points = {'x': [0, 1, 2, 3, 4],
              'y': [0, 2, 4, 1, 3]}
    errors = {'x': [[0.1, 0.4],
                    [0.2, 0.3],
                    [0.3, 0.2],
                    [0.4, 0.1],
                    [0.45, 0.05]
                   ],
              'y': [[0.4, 0.1],
                    [0.3, 0.2],
                    [0.2, 0.3],
                    [0.1, 0.4],
                    [0.05, 0.45]]}
    
    scatter = plotly.graph_objs.Scatter(x=points['x'],
                                        y=points['y'],
                                        error_x={'type': 'data',
                                                 'array': [e[1] for e in errors['x']],
                                                 'arrayminus': [e[0] for e in errors['x']],
                                                 'symmetric': False
                                                },
                                        error_y={'type': 'data',
                                                 'array': [e[1] for e in errors['y']],
                                                 'arrayminus': [e[0] for e in errors['y']],
                                                 'symmetric': False
                                                },                                    
                                        mode='markers')
    shapes = list()
    for i in range(len(errors['x'])):
        shapes.append({'x0': points['x'][i] - errors['x'][i][0],
                       'y0': points['y'][i] - errors['y'][i][0],
                       'x1': points['x'][i] + errors['x'][i][1],
                       'y1': points['y'][i] + errors['y'][i][1],
                       'fillcolor': 'rgb(160, 0, 0)',
                       'layer': 'below',
                       'line': {'width': 0}
                      })
    layout = plotly.graph_objs.Layout(shapes=shapes)
    data = plotly.graph_objs.Data([scatter], error_x=[e[0] for e in errors['x']])
    fig = plotly.graph_objs.Figure(data=data, layout=layout)
    plotly.offline.iplot(fig)