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

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


当前回答

我只使用字符串“左中”作为位置,就像在MATLAB中一样。

我从Matplotlib导入了pylab。

代码如下:

from matplotlib as plt
from matplotlib.font_manager import FontProperties

t = A[:, 0]
sensors = A[:, index_lst]

for i in range(sensors.shape[1]):
    plt.plot(t, sensors[:, i])

plt.xlabel('s')
plt.ylabel('°C')
lgd = plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), fancybox = True, shadow = True)

其他回答

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

你也可以试试figlegend。可以创建独立于任何Axes对象的图例。但是,您可能需要创建一些“虚拟”路径,以确保正确传递对象的格式。

有很多方法可以做你想做的事。为了补充Christian Alis和Navi已经说过的内容,您可以使用bbox_To_anchor关键字参数将图例部分放在轴外和/或减小字体大小。

在考虑减小字体大小(这可能会使内容非常难以阅读)之前,请尝试将图例放在不同的位置:

因此,让我们从一个通用示例开始:

import matplotlib.pyplot as plt
import numpy as np

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)

ax.legend()

plt.show()

如果我们做同样的事情,但使用bbox_to_anchor关键字参数,我们可以将图例稍微移到轴边界之外:

import matplotlib.pyplot as plt
import numpy as np

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)

ax.legend(bbox_to_anchor=(1.1, 1.05))

plt.show()

类似地,使图例更水平和/或放在图的顶部(我还打开了圆角和简单的阴影):

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

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

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

ax.legend(loc='upper center', bbox_to_anchor=(0.5, 1.05),
          ncol=3, fancybox=True, shadow=True)
plt.show()

或者,缩小当前绘图的宽度,并将图例完全放在图形的轴之外(注意:如果使用了tight_layout(),则省略ax.set_position():

import matplotlib.pyplot as plt
import numpy as np

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)

# Shrink current axis by 20%
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])

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

plt.show()

以类似的方式,垂直缩小绘图,并在底部放置一个水平图例:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

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

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

# Shrink current axis's height by 10% on the bottom
box = ax.get_position()
ax.set_position([box.x0, box.y0 + box.height * 0.1,
                 box.width, box.height * 0.9])

# Put a legend below current axis
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05),
          fancybox=True, shadow=True, ncol=5)

plt.show()

查看matplotlib图例指南。您还可以查看plt.figlegend()。

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

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

放置图例(bbox_to_anchor)

使用plt.legend的loc参数将图例定位在轴的边界框内。例如,loc=“右上角”将图例放置在边界框的右上角,默认情况下,在坐标轴坐标(或边界框符号(x0,y0,width,height)=(0,0,1,1))中,图例范围从(0,1)到(1,1,0)。

要将图例放置在轴边界框之外,可以指定图例左下角的轴坐标元组(x0,y0)。

plt.legend(loc=(1.04, 0))

一种更通用的方法是使用bbox_to_anchor参数手动指定图例应放置的边界框。一个人可以限制自己只供应bbox的(x0,y0)部分。这将创建一个零跨度框,图例将沿loc参数给定的方向展开。例如。,

plt.legend(bbox_to_anchor=(1.04,1),loc=“左上”)

将图例放置在轴外,使图例的左上角位于轴坐标中的位置(1.04,1)。

下面给出了进一步的例子,其中还显示了模式和ncols等不同参数之间的相互作用。

l1 = plt.legend(bbox_to_anchor=(1.04, 1), borderaxespad=0)
l2 = plt.legend(bbox_to_anchor=(1.04, 0), loc="lower left", borderaxespad=0)
l3 = plt.legend(bbox_to_anchor=(1.04, 0.5), loc="center left", borderaxespad=0)
l4 = plt.legend(bbox_to_anchor=(0, 1.02, 1, 0.2), loc="lower left",
                mode="expand", borderaxespad=0, ncol=3)
l5 = plt.legend(bbox_to_anchor=(1, 0), loc="lower right",
                bbox_transform=fig.transFigure, ncol=3)
l6 = plt.legend(bbox_to_anchor=(0.4, 0.8), loc="upper right")

关于如何将4元组参数解释为bbox_to_anchor(如l4中所示)的详细信息,可以在这个问题中找到。mode=“expand”在4元组给定的边界框内水平展开图例。有关垂直展开的图例,请参阅此问题。

有时,在图形坐标而不是轴坐标中指定边界框可能很有用。这在上面的示例l5中显示,其中使用bbox_transform参数将图例放在图的左下角。

后处理

将图例放置在轴之外通常会导致不希望出现的情况,即图例完全或部分位于图形画布之外。

此问题的解决方案包括:

调整子批次参数可以通过使用plt.subplots_adjust来调整子图参数,使得轴在图形内占用更少的空间(从而为图例留出更多的空间)。例如。,plt.sublots_adjust(右=0.7)在图的右侧留下30%的空间,可以放置图例。紧凑的布局使用plt.tight_layout允许自动调整子地块参数,使图形中的元素紧靠图形边缘。不幸的是,在这种自动化中没有考虑图例,但我们可以提供一个矩形框,整个子地块区域(包括标签)都可以放入其中。plt.tight_layout(矩形=[0,0,0.75,1])使用bbox_inches=“tight”保存图形参数bbox_inches=“tight”to plt.savefig可用于保存图形,以便画布上的所有艺术家(包括图例)都适合保存的区域。如果需要,将自动调整图形大小。plt.savefig(“output.png”,bbox_inches=“紧”)自动调整子批次参数在这个答案中可以找到一种自动调整子绘图位置的方法,以使图例适合画布内部而不改变图形大小:创建具有精确大小且无填充的图形(以及轴外部的图例)

上述案例的比较:

选择

图形图例

可以对图形使用图例而不是轴matplotlib.figure.figure.legend。这对于matplotlib 2.1版或更高版本特别有用,因为不需要特殊参数

fig.legend(loc=7)

为图形不同轴上的所有艺术家创建图例。图例使用loc参数放置,类似于将其放置在轴内的方式,但参考了整个图形-因此它将在一定程度上自动位于轴外。剩下的是调整子图,使图例和轴之间没有重叠。这里,上面的“调整子地块参数”一点将很有帮助。例如:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2*np.pi)
colors = ["#7aa0c4", "#ca82e1", "#8bcd50", "#e18882"]
fig, axes = plt.subplots(ncols=2)
for i in range(4):
    axes[i//2].plot(x, np.sin(x+i), color=colors[i], label="y=sin(x + {})".format(i))

fig.legend(loc=7)
fig.tight_layout()
fig.subplots_adjust(right=0.75)
plt.show()

专用子槽轴内的图例

使用bbox_to_anchor的另一种选择是将图例放置在其专用的子地块轴(lax)中。由于图例子图应该小于图,因此我们可以在创建轴时使用gridsec_kw={“width_ratios”:[4]}。我们可以隐藏轴lax.axis(“off”),但我们仍然在其中放置图例。图例句柄和标签需要通过h,l=ax.get_legend_handles_labels()从真实绘图中获得,然后可以提供给lax.legend(h,l)子绘图中的图例。下面是一个完整的示例。

import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = 6, 2

fig, (ax, lax) = plt.subplots(ncols=2, gridspec_kw={"width_ratios":[4, 1]})
ax.plot(x, y, label="y=sin(x)")
....

h, l = ax.get_legend_handles_labels()
lax.legend(h, l, borderaxespad=0)
lax.axis("off")

plt.tight_layout()
plt.show()

这会生成一个与上面的图在视觉上非常相似的图:

我们也可以使用第一个轴来放置图例,但使用图例轴的bbox_transform,

ax.legend(bbox_to_anchor=(0, 0, 1, 1), bbox_transform=lax.transAxes)
lax.axis("off")

在这种方法中,我们不需要从外部获取图例句柄,但需要指定bbox_to_anchor参数。

进一步阅读和注释:

考虑一下Matplotlib图例指南以及您想使用图例进行的其他操作的一些示例。在回答这个问题时,可以直接找到一些为饼图放置图例的示例代码:Python-图例与饼图重叠loc参数可以采用数字而不是字符串,这会使调用变短,但它们之间的映射不是很直观。以下是供参考的映射: