Search code examples
matplotliblegendcenteringfigurelegend-properties

How to use mode='expand' and center a figure-legend label given only one label entry?


I would like to generate a centered figure legend for subplot(s), for which there is a single label. For my actual use case, the number of subplot(s) is greater than or equal to one; it's possible to have a 2x2 grid of subplots and I would like to use the figure-legend instead of using ax.legend(...) since the same single label entry will apply to each/every subplot.

As a brief and simplified example, consider the code just below:

import numpy as np
import matplotlib.pyplot as plt

x = np.arange(10)
y = np.sin(x)

fig, ax = plt.subplots()
ax.plot(x, y, color='orange', label='$f(x) = sin(x)$')
fig.subplots_adjust(bottom=0.15)
fig.legend(mode='expand', loc='lower center')
plt.show()
plt.close(fig)

This code will generate the figure seen below:

example plot with mode

I would like to use the mode='expand' kwarg to make the legend span the entire width of the subplot(s); however, doing so prevents the label from being centered. As an example, removing this kwarg from the code outputs the following figure.

example without mode

Is there a way to use both mode='expand' and also have the label be centered (since there is only one label)?

EDIT:

I've tried using the bbox_to_anchor kwargs (as suggested in the docs) as an alternative to mode='expand', but this doesn't work either. One can switch out the fig.legend(...) line for the line below to test for yourself.

fig.legend(loc='lower center', bbox_to_anchor=(0, 0, 1, 0.5))

Solution

  • The handles and labels are flush against the left side of the legend. There is no mechanism to allow for aligning them.
    A workaround could be to use 3 columns of legend handles and fill the first and third with a transparent handle.

    import numpy as np
    import matplotlib.pyplot as plt
    
    x = np.arange(10)
    y = np.sin(x)
    
    fig, ax = plt.subplots()
    fig.subplots_adjust(bottom=0.15)
    
    line, = ax.plot(x, y, color='orange', label='$f(x) = sin(x)$')
    
    proxy = plt.Rectangle((0,0),1,1, alpha=0)
    fig.legend(handles=[proxy, line, proxy], mode='expand', loc='lower center', ncol=3)
    plt.show()
    

    enter image description here