1

I would like to adjust the height of the errorbars as shown in the matplotlib legend, so as to avoid that they are bumping into each other (shown below).

I'm aware of this post Matplotlib: Don't show errorbars in legend that discusses how to remove the errorbars, but I don't know what to do to adjust the handler so that the error bars are still there, just shortened.

Error bars

A working example with overlapping errorbars is:

import matplotlib
font = {'family' : 'serif',
    'serif': 'Computer Modern Roman',
    'weight' : 'medium',
    'size'   : 19}
matplotlib.rc('font', **font)
matplotlib.rc('text', usetex=True)

fig,ax1=plt.subplots()  
h0=ax1.errorbar([1,2,3],[1,2,3],[1,2,1],c='b',label='$p=5$')
h1=ax1.errorbar([1,2,3],[3,2,1],[1,1,1],c='g',label='$p=5$')
hh=[h0,h1]
ax1.legend(hh,[H.get_label() for H in hh],bbox_to_anchor=(0.02, 0.9, 1., .102),loc=1,labelspacing=0.01, handlelength=0.14, handletextpad=0.4,frameon=False, fontsize=18.5)

I'm using version 1.5.1 of matplotlib, but I don't think that that's the issue.

mzzx
  • 1,964
  • 4
  • 16
  • 26
  • By default, there should be enough spacing between the legend entries; a legend would look [like this](https://i.stack.imgur.com/yQr0V.png). What did you change compared to the default? If you want help, you need to provide a [mcve] of the code that you have a problem with (and also clearly state the version of matplotlib you are using). – ImportanceOfBeingErnest Sep 07 '17 at 10:32
  • Thanks - I agree, I needed to use the labelspacing keyword in the legend because I'm squeezing the legend into a corner of the plot. Posting the code now. – mzzx Sep 07 '17 at 10:42

1 Answers1

3

You can use the handler_map kwarg to ax.legend to control the legend handles.

In this case, you want to use the HandlerErrorbar handler from matplotlib.legend_handler, and set the xerr_size option. By default, this is 0.5, so we just need to reduce that number to something approriate for the plot.

Taking guidance from the legend guide, we can see how to use handler_map. To just change one of the errorbar handles, we could do this:

handler_map={h0: HandlerErrorbar(xerr_size=0.3)}

Assuming you want to change all of the errorbar handles in the same way, you can change h0 to type(h0):

handler_map={type(h0): HandlerErrorbar(xerr_size=0.3)}

Note that this is just a quick way to tell handler_map how to change all Errorbars. Note that this is equivalent to doing the following:

from matplotlib.container import ErrorbarContainer
...
ax1.legend(...
    handler_map={ErrorbarContainer: HandlerErrorbar(xerr_size=0.3)}
    ...)

Using the type(h0) shorthand just means you don't need to have the extra import of ErrorbarContainer.

Putting this together in your minimal example:

import matplotlib
import matplotlib.pyplot as plt

# Import the handler
from matplotlib.legend_handler import HandlerErrorbar

font = {'family' : 'serif',
    'serif': 'Computer Modern Roman',
    'weight' : 'medium',
    'size'   : 19}
matplotlib.rc('font', **font)
matplotlib.rc('text', usetex=True)

fig,ax1=plt.subplots()  
h0=ax1.errorbar([1,2,3],[1,2,3],[1,2,1],c='b',label='$p=5$')
h1=ax1.errorbar([1,2,3],[3,2,1],[1,1,1],c='g',label='$p=5$')
hh=[h0,h1]
ax1.legend(
        hh, [H.get_label() for H in hh],
        handler_map={type(h0): HandlerErrorbar(xerr_size=0.3)},  # adjust xerr_size to suit the plot
        bbox_to_anchor=(0.02, 0.9, 1., .102),
        loc=1, labelspacing=0.01, 
        handlelength=0.14, handletextpad=0.4,
        frameon=False, fontsize=18.5)

plt.show()

enter image description here

For proof this has worked, you can compare this to the original image, before I adjusted the errorbar sizes:

enter image description here

tmdavison
  • 64,360
  • 12
  • 187
  • 165
  • Thanks, this works great and is super helpful! Just so I understand - what does the type(h0) do? I understand it changes all the errorbars - but why? Does it mean: every handler of type (h0)? – mzzx Sep 07 '17 at 12:31
  • Yes, `type(h0)` is `matplotlib.container.ErrorbarContainer`, so its basically saying to control all `ErrorbarContainer`s in the same way. I'll make that clearer in my answer... – tmdavison Sep 07 '17 at 12:44
  • Ok thanks, I get it. Many thanks for the explanation!! – mzzx Sep 07 '17 at 12:57