Matplotlib: Adjust size/height of errorbars in legend

1.8k views Asked by At

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.

1

There are 1 answers

3
tmdavison On BEST ANSWER

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