如何将传说放在剧情之外

2022-09-05 00:56:56

我有一系列20个情节(不是子情节)要在一个数字中制作。我希望这个传奇是开箱即用的。同时,我不想改变轴,因为图形的大小减小了。

  1. 我想将图例框保留在绘图区域之外(我希望图例位于绘图区域右侧的外部)。
  2. 有没有办法减小图例框内文本的字体大小,使图例框的大小变小?

答案 1

有很多方法可以做你想做的事。为了补充Christian AlisNavi已经说过的内容,您可以使用关键字参数将图例部分放在轴外和/或减小字体大小。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()

alt text

如果我们做同样的事情,但使用关键字参数,我们可以将图例稍微移出轴边界: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()

Alt text

同样,使图例更水平和/或将其放在图的顶部(我也打开了圆角和简单的投影):

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

alt text

或者,缩小当前图的宽度,并将图例完全放在图轴之外(注意:如果使用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()

Alt text

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

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

Alt text

看看matplotlib传奇指南。你也可以看看plt.figlegend()。


答案 2

放置图例 (bbox_to_anchor)

图例位于轴的边界框内,使用参数 plt.legend
例如,将图例放在边界框的右上角,默认情况下,该边界框以轴坐标(或边界框表示法)从 到 的范围。locloc="upper right"(0, 0)(1, 1)(x0, y0, width, height) = (0, 0, 1, 1)

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

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

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

plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left")

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

下面给出了更多的例子,其中还显示了不同参数之间的相互作用,如和。modencols

Enter image description here

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 元组参数解释为 (如 中 所示)的详细信息,可以在此问题中找到。在由 4 元组给出的边界框内水平扩展图例。有关垂直展开的图例,请参阅此问题bbox_to_anchorl4mode="expand"

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

后处理

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

此问题的解决方案有:

  • 调整子图参数
    可以使用plt.subplots_adjust来调整子图参数,使轴占用较少的图空间(从而为图例留出更多空间)。例如,

    plt.subplots_adjust(right=0.7)
    

    在图的右侧留出 30% 的空间,可以放置图例。

  • 紧凑布局
    使用plt.tight_layout 允许自动调整子图参数,使图中的元素紧贴图形边缘。不幸的是,在这种自动性中没有考虑图例,但是我们可以提供一个整个子图区域(包括标注)将适合的矩形框。

    plt.tight_layout(rect=[0, 0, 0.75, 1])
    
  • 保存带有bbox_inches = “tight”
    的图形 plt.savefig 的参数可用于保存图形,以便画布上的所有艺术家(包括图例)都适合保存的区域。如果需要,数字大小会自动调整。bbox_inches = "tight"

    plt.savefig("output.png", bbox_inches="tight")
    
  • 自动调整子图参数
    一种自动调整子图位置的方法,使图例适合画布内部而不更改图形大小,可以在以下答案中找到:创建具有精确大小且无填充的图形(以及轴外的图例)

上述案例之间的比较:

Enter image description here

选择

人物图例

可以使用图例而不是轴,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()

Enter image description here

专用子图轴内的图例

使用的替代方法是将图例放置在其专用的子图轴中 ()。由于图例子图应小于图,因此我们可以在轴创建时使用。我们可以隐藏轴,但我们仍然放了一个图例。图例句柄和标注需要通过从真实图中获取,然后可以提供给子图中的图例。下面是一个完整的示例。bbox_to_anchorlaxgridspec_kw={"width_ratios":[4, 1]}lax.axis("off")h, l = ax.get_legend_handles_labels()laxlax.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()

这会产生一个在视觉上与上面的情节非常相似的情节:

Enter image description here

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

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

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

进一步阅读和注意事项:

  • 考虑一下 Matplotlib 图例指南,其中包含一些您想要对图例执行的其他操作的示例。
  • 在回答以下问题时,可以直接找到一些用于放置饼图图例的示例代码:Python - 图例与饼图重叠
  • 该参数可以采用数字而不是字符串,这使得调用更短,但是,它们不是很直观地相互映射。以下是供参考的映射:loc

Enter image description here