python-3.xmatplotlibploterrorbar

How to alter the size of the arrow while plotting upper (lower) limits in matplotlib?


I want to represent unconstrained data with an arrow marking upper (or lower) limit. To do this, I generate a boolean array lim and feed it as: plt.errorbar(x, y, yerr=y_err, uplims=lim, ls='none'). In the default case, the length of the arrows is not what I want. I want them longer in some cases and shorter in other. For example, in the plot below the size of the arrow in the first data point (brown) is about 0.5. Since another point (pink) lies above the arrow head it is not clear if there is an arrow. I want the arrow size to be 0.25 instead.:

enter image description here

So basically, how can I manually control the size of the arrows?


Solution

  • If we start with part of this errorbar example, e.g.,

    import matplotlib.pyplot as plt
    import numpy as np
    
    # example data
    x = np.array([0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0])
    y = np.exp(-x)
    xerr = 0.1
    yerr = 0.2
    
    # lower & upper limits of the error
    lolims = np.array([0, 0, 1, 0, 1, 0, 0, 0, 1, 0], dtype=bool)
    uplims = np.array([0, 1, 0, 0, 0, 1, 0, 0, 0, 1], dtype=bool)
    ls = 'dotted'
    
    fig, ax = plt.subplots(figsize=(7, 4))
    
    # including upper limits
    eb = ax.errorbar(x, y, xerr=xerr, yerr=yerr, uplims=uplims,
                     linestyle=ls)
    

    then eb is an

    <ErrorbarContainer object of 3 artists>
    

    and if we look at eb.lines we see:

    (<matplotlib.lines.Line2D at 0x7ff9e7520d30>,
     (<matplotlib.lines.Line2D at 0x7ff9e7522e90>,),
     (<matplotlib.collections.LineCollection at 0x7ff9e75211e0>,
      <matplotlib.collections.LineCollection at 0x7ff9e7522a40>))
    

    The second item in this tuple is a 1-tuple containing the Line2D object for the upper limit arrow head points, e.g.,

    eb.lines[1][0].get_xydata()
    array([[ 1.        ,  0.16787944],
           [ 3.        , -0.15021293],
           [ 5.        , -0.19326205]])
    

    So, we can set the markersize in this Line2d object to make the arrows bigger (going from the default of 6 to 10):

    eb.lines[1][0].set_markersize(10)
    

    which gives:

    enter image description here