我有一系列20幅图(不是子图)要在一个图中绘制。我希望图例在框外。同时,我不想改变轴,因为图形的大小会变小。

我希望图例框位于绘图区域之外(我希望图例位于绘图区域的右侧)。有没有办法减小图例框内文本的字体大小,使图例框的大小变小?


当前回答

简短回答:您可以使用bbox_to_anchor+bbox_extra_artists+bbox_inches='ight'。


更长的答案:您可以使用bbox_to_anchor手动指定图例框的位置,正如其他人在答案中指出的那样。

然而,常见的问题是图例框被裁剪,例如:

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和bbox_inches要求savefig在保存的图像中包含裁剪的元素:

图savefig('image_output.png',bbox_extra_artits=(lgd,),bbox_inches='ight')

示例(我只更改了最后一行,在图savefig()中添加了2个参数):

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')

我希望matplotlib能够像Matlab那样允许图例框的外部位置:

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])

其他回答

从Joe的代码开始,这个方法修改了窗口宽度,以自动适应图右侧的图例。

import matplotlib.pyplot as plt
import numpy as np

plt.ion()

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$'%i)

# Put a legend to the right of the current axis
leg = ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))

plt.draw()

# Get the ax dimensions.
box = ax.get_position()
xlocs = (box.x0,box.x1)
ylocs = (box.y0,box.y1)

# Get the figure size in inches and the dpi.
w, h = fig.get_size_inches()
dpi = fig.get_dpi()

# Get the legend size, calculate new window width and change the figure size.
legWidth = leg.get_window_extent().width
winWidthNew = w*dpi+legWidth
fig.set_size_inches(winWidthNew/dpi,h)

# Adjust the window size to fit the figure.
mgr = plt.get_current_fig_manager()
mgr.window.wm_geometry("%ix%i"%(winWidthNew,mgr.window.winfo_height()))

# Rescale the ax to keep its original size.
factor = w*dpi/winWidthNew
x0 = xlocs[0]*factor
x1 = xlocs[1]*factor
width = box.width*factor
ax.set_position([x0,ylocs[0],x1-x0,ylocs[1]-ylocs[0]])

plt.draw()

只需在plot()调用之后调用legend(),如下所示:

# 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))

结果如下:

简短回答:在图例上调用可拖动功能,并将其交互式移动到您想要的任何位置:

ax.legend().draggable()

长篇大论:如果您更喜欢交互式/手动放置图例,而不是以编程方式放置图例,则可以切换图例的可拖动模式,以便将其拖动到任何位置。检查以下示例:

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()

更新版本的Matplotlib使图例更容易定位在绘图之外。我使用Matplotlib版本3.1.1生成了这个示例。

用户可以向loc参数传递2元组坐标,以将图例定位在边界框中的任何位置。唯一的问题是,您需要运行plt.tight_layout()来获取matplotlib以重新计算绘图尺寸,以便图例可见:

import matplotlib.pyplot as plt

plt.plot([0, 1], [0, 1], label="Label 1")
plt.plot([0, 1], [0, 2], label='Label 2')

plt.legend(loc=(1.05, 0.5))
plt.tight_layout()

这导致以下绘图:

参考文献:

matplotlib.pyplot.legend

简短回答:您可以使用bbox_to_anchor+bbox_extra_artists+bbox_inches='ight'。


更长的答案:您可以使用bbox_to_anchor手动指定图例框的位置,正如其他人在答案中指出的那样。

然而,常见的问题是图例框被裁剪,例如:

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和bbox_inches要求savefig在保存的图像中包含裁剪的元素:

图savefig('image_output.png',bbox_extra_artits=(lgd,),bbox_inches='ight')

示例(我只更改了最后一行,在图savefig()中添加了2个参数):

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')

我希望matplotlib能够像Matlab那样允许图例框的外部位置:

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])