Search code examples
pythonmatplotliberrorbar

Matplotlib asymmetric yerr way off


As far as I can tell, matplotlib is just plotting incorrect values for my error bars. I've simplified my code as far as I can, down to hard-coding in values and things are still wrong... In the following example, I've plotted the exact same values through scatter, and they appear where I would expect them to - but the error bars are miles off. Have I misunderstood something?

Minimal example:

from matplotlib.pyplot import *

x = [1, 2, 3, 4, 5]
y = [5, 11, 22, 44, 88]
err = [[4.3, 10.1, 19.8, 40, 81.6],
       [5.9, 13.6, 24.6, 48.5, 100.2]]

figure();
errorbar(x, y, yerr=err, label="data")
scatter(x, err[0], c='r', label="lower limit")
scatter(x, err[1], c='g', label="upper limit")

legend()
show()

Result:Result of the code sample above


Solution

  • As @Bart pointed out in the comments, matplotlib interprets yerr as a set of +/- offsets relative to the y-coordinates of the line. From the documentation:

    xerr/yerr: [ scalar | N, Nx1, or 2xN array-like ]

    If a scalar number, len(N) array-like object, or an Nx1 array-like object, errorbars are drawn at +/- value relative to the data.

    If a sequence of shape 2xN, errorbars are drawn at -row1 and +row2 relative to the data.

    You can get the effect you're looking for by taking the absolute difference between y and err:

    err = np.array(err)
    y = np.array(y)
    offsets = np.abs(err - y[None, :])
    
    figure();
    errorbar(x, y, yerr=offsets, label="data")
    scatter(x, err[0], c='r', label="lower limit")
    scatter(x, err[1], c='g', label="upper limit")
    legend()
    show()
    

    enter image description here