Get legend as a separate picture in Matplotlib

You may limit the saved region of a figure to the bounding box of the legend using the bbox_inches argument to fig.savefig. Below to versions of a function which you can simply call with the legend you want to save as argument. You may either use the legend created in the original figure here (and remove it afterwards, legend.remove()) or you may create a new figure for the legend and simply use the function as it is.

Export legend boundingbox

In case the complete legend shall be saved, the bounding box supplied to the bbox_inches argument would be simply the transformed bounding box of the legend. This works well if the legend has no border around it.

import matplotlib.pyplot as plt

colors = ["crimson", "purple", "gold"]
f = lambda m,c: plt.plot([],[],marker=m, color=c, ls="none")[0]
handles = [f("s", colors[i]) for i in range(3)]
labels = colors
legend = plt.legend(handles, labels, loc=3, framealpha=1, frameon=False)

def export_legend(legend, filename="legend.png"):
    fig  = legend.figure
    fig.canvas.draw()
    bbox  = legend.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
    fig.savefig(filename, dpi="figure", bbox_inches=bbox)

export_legend(legend)
plt.show()

enter image description here

Export extended legend bounding box

If there is a border around the legend, the above solution may be suboptimal. In this case it makes sense to extend the bounding box by some pixels to include the border to its full.

import numpy as np
import matplotlib.pyplot as plt

colors = ["crimson", "purple", "gold"]
f = lambda m,c: plt.plot([],[],marker=m, color=c, ls="none")[0]
handles = [f("s", colors[i]) for i in range(3)]
labels = colors
legend = plt.legend(handles, labels, loc=3, framealpha=1, frameon=True)

def export_legend(legend, filename="legend.png", expand=[-5,-5,5,5]):
    fig  = legend.figure
    fig.canvas.draw()
    bbox  = legend.get_window_extent()
    bbox = bbox.from_extents(*(bbox.extents + np.array(expand)))
    bbox = bbox.transformed(fig.dpi_scale_trans.inverted())
    fig.savefig(filename, dpi="figure", bbox_inches=bbox)

export_legend(legend)
plt.show()

enter image description here


This could work:

import pylab
fig = pylab.figure()
figlegend = pylab.figure(figsize=(3,2))
ax = fig.add_subplot(111)
lines = ax.plot(range(10), pylab.randn(10), range(10), pylab.randn(10))
figlegend.legend(lines, ('one', 'two'), 'center')
fig.show()
figlegend.show()
figlegend.savefig('legend.png')

alt text


It is possible to use axes.get_legend_handles_labels to get the legend handles and labels from one axes object and to use them to add them to an axes in a different figure.

# create a figure with one subplot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([1,2,3,4,5], [1,2,3,4,5], 'r', label='test')
# save it *without* adding a legend
fig.savefig('image.png')

# then create a new image
# adjust the figure size as necessary
figsize = (3, 3)
fig_leg = plt.figure(figsize=figsize)
ax_leg = fig_leg.add_subplot(111)
# add the legend from the previous axes
ax_leg.legend(*ax.get_legend_handles_labels(), loc='center')
# hide the axes frame and the x/y labels
ax_leg.axis('off')
fig_leg.savefig('legend.png')

If for some reason you want to hide only the axes label, you can use:

ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)

or if, for some weirder reason, you want to hide the axes frame but not the axes labels you can use:

ax.set_frame_on(False)

ps: this answer has been adapted from my answer to a duplicate question


use pylab.figlegend(..) and get_legend_handles_labels(..):

import pylab, numpy 
x = numpy.arange(10)

# create a figure for the data
figData = pylab.figure()
ax = pylab.gca()

for i in xrange(3):
    pylab.plot(x, x * (i+1), label='line %d' % i)

# create a second figure for the legend
figLegend = pylab.figure(figsize = (1.5,1.3))

# produce a legend for the objects in the other figure
pylab.figlegend(*ax.get_legend_handles_labels(), loc = 'upper left')

# save the two figures to files
figData.savefig("plot.png")
figLegend.savefig("legend.png")

It can be tricky though to get the size of the legend figure right in an automated manner.