I have a series of 20 plots (not subplots) to be made in a single figure. I want the legend to be outside of the box. At the same time, I do not want to change the axes, a
Short answer: you can use bbox_to_anchor
+ bbox_extra_artists
+ bbox_inches='tight'
.
Longer answer:
You can use bbox_to_anchor
to manually specify the location of the legend box, as some other people have pointed out in the answers.
However, the usual issue is that the legend box is cropped, e.g.:
import matplotlib.pyplot as plt
# data
all_x = [10,20,30]
all_y = [[1,3], [1.5,2.9],[3,2]]
# Plot
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(all_x, all_y)
# Add legend, title and axis labels
lgd = ax.legend( [ 'Lag ' + str(lag) for lag in all_x], loc='center right', bbox_to_anchor=(1.3, 0.5))
ax.set_title('Title')
ax.set_xlabel('x label')
ax.set_ylabel('y label')
fig.savefig('image_output.png', dpi=300, format='png')
In order to prevent the legend box from getting cropped, when you save the figure you can use the parameters bbox_extra_artists
and bbox_inches
to ask savefig
to include cropped elements in the saved image:
fig.savefig('image_output.png', bbox_extra_artists=(lgd,), bbox_inches='tight')
Example (I only changed the last line to add 2 parameters to fig.savefig()
):
import matplotlib.pyplot as plt
# data
all_x = [10,20,30]
all_y = [[1,3], [1.5,2.9],[3,2]]
# Plot
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(all_x, all_y)
# Add legend, title and axis labels
lgd = ax.legend( [ 'Lag ' + str(lag) for lag in all_x], loc='center right', bbox_to_anchor=(1.3, 0.5))
ax.set_title('Title')
ax.set_xlabel('x label')
ax.set_ylabel('y label')
fig.savefig('image_output.png', dpi=300, format='png', bbox_extra_artists=(lgd,), bbox_inches='tight')
I wish that matplotlib would natively allow outside location for the legend box as Matlab does:
figure
x = 0:.2:12;
plot(x,besselj(1,x),x,besselj(2,x),x,besselj(3,x));
hleg = legend('First','Second','Third',...
'Location','NorthEastOutside')
% Make the text of the legend italic and color it brown
set(hleg,'FontAngle','italic','TextColor',[.3,.2,.1])
Short Answer: Invoke draggable on the legend and interactively move it wherever you want:
ax.legend().draggable()
Long Answer: If you rather prefer to place the legend interactively/manually rather than programmatically, you can toggle the draggable mode of the legend so that you can drag it to wherever you want. Check the example below:
import matplotlib.pylab as plt
import numpy as np
#define the figure and get an axes instance
fig = plt.figure()
ax = fig.add_subplot(111)
#plot the data
x = np.arange(-5, 6)
ax.plot(x, x*x, label='y = x^2')
ax.plot(x, x*x*x, label='y = x^3')
ax.legend().draggable()
plt.show()
To place the legend outside the plot area, use loc
and bbox_to_anchor
keywords of legend()
. For example, the following code will place the legend to the right of the plot area:
legend(loc="upper left", bbox_to_anchor=(1,1))
For more info, see the legend guide
Just call legend()
call after the plot()
call like this:
# matplotlib
plt.plot(...)
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
# Pandas
df.myCol.plot().legend(loc='center left', bbox_to_anchor=(1, 0.5))
Results would look something like this:
set_size
of FontProperties
.import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
fontP = FontProperties()
fontP.set_size('xx-small')
p1, = plt.plot([1, 2, 3], label='Line 1')
p2, = plt.plot([3, 2, 1], label='Line 2')
plt.legend(handles=[p1, p2], title='title', bbox_to_anchor=(1.05, 1), loc='upper left', prop=fontP)
fontsize='xx-small'
also works, without importing FontProperties
.plt.legend(handles=[p1, p2], title='title', bbox_to_anchor=(1.05, 1), loc='upper left', fontsize='xx-small')
Not exactly what you asked for, but I found it's an alternative for the same problem. Make the legend semi-transparant, like so:
Do this with:
fig = pylab.figure()
ax = fig.add_subplot(111)
ax.plot(x,y,label=label,color=color)
# Make the legend transparent:
ax.legend(loc=2,fontsize=10,fancybox=True).get_frame().set_alpha(0.5)
# Make a transparent text box
ax.text(0.02,0.02,yourstring, verticalalignment='bottom',
horizontalalignment='left',
fontsize=10,
bbox={'facecolor':'white', 'alpha':0.6, 'pad':10},
transform=self.ax.transAxes)