图例与饼图重叠。

46

在Python中使用matplotlib。图例与我的饼图重叠。尝试了各种“loc”选项,如“best”,1,2,3...但都无济于事。有什么建议可以精确地指定图例位置(例如在饼图边界上给出填充)或者至少确保它不重叠吗?

1个回答

133

简短回答:可以使用 plt.legend 的参数 locbbox_to_anchor,以及额外的 bbox_transformmode 来将图例放置在坐标轴或图形中。


详细回答:

第一步:确保需要图例。

在许多情况下,根本不需要图例,信息可以从上下文或颜色直接推断出来:

enter image description here

enter image description here

如果确实需要图例,请继续第二步。

第二步:确定需要饼图。

在许多情况下,饼图并不是传达信息的最佳方式。

enter image description here

如果明确确定需要饼图,请继续放置图例。

放置图例

plt.legend() 有两个主要参数来确定图例的位置。最重要的并且足够作为一个参数的是 loc 参数。
例如,plt.legend(loc="upper left") 将图例放置在其边界框的左上角。如果没有指定更多的参数,则该边框将是整个坐标轴。

但是,我们可以使用 bbox_to_anchor 参数指定自己的边界框。如果给出一个二元组,例如 bbox_to_anchor=(1,1),它表示边界框位于坐标轴的右上角并且没有范围。然后根据 loc 参数相对于该点放置图例。然后它将扩展到零大小的边界框之外。例如,如果 loc"upper left",则图例的左上角位于位置 (1,1),图例将向右和向下扩展。

这个概念用于上面的图,告诉我们关于环球小姐选举中偏见的令人震惊的真相。

import matplotlib.pyplot as plt
import matplotlib.patches

total = [100]
labels = ["Earth", "Mercury", "Venus", "Mars", "Jupiter",  "Saturn", 
           "Uranus", "Neptune", "Pluto *"]
plt.title('Origin of Miss Universe since 1952')
plt.gca().axis("equal")
pie = plt.pie(total, startangle=90, colors=[plt.cm.Set3(0)],
                            wedgeprops = { 'linewidth': 2, "edgecolor" :"k" })
handles = []
for i, l in enumerate(labels):
    handles.append(matplotlib.patches.Patch(color=plt.cm.Set3((i)/8.), label=l))
plt.legend(handles,labels, bbox_to_anchor=(0.85,1.025), loc="upper left")
plt.gcf().text(0.93,0.04,"* out of competition since 2006", ha="right")
plt.subplots_adjust(left=0.1, bottom=0.1, right=0.75)

为了避免图例超出图形,我们使用plt.subplots_adjust获取图形边缘和轴之间的更多空间,这可以被图例利用。

还可以使用4元组选项来使用bbox_to_anchor。如何使用或解释这个内容在这个问题中有详细介绍:What does a 4-element tuple argument for 'bbox_to_anchor' mean in matplotlib?,并且可以使用mode="expand"参数使图例适合指定的边界框。

这种方法有一些有用的替代方案:

使用图形坐标

不是在轴坐标中指定图例位置,而是可以使用图形坐标。优点是这将允许简单地将图例放置在图形的一个角落,而不需要调整其他部分太多。为此,可以使用bbox_transform参数并将图形转换提供给它。然后会将给定给bbox_to_anchor的坐标解释为图形坐标。

plt.legend(pie[0],labels, bbox_to_anchor=(1,0), loc="lower right", 
                          bbox_transform=plt.gcf().transFigure)

这里(1,0)是图形的右下角。由于轴和图形边缘之间的默认间距,这足以放置图例,使其不与饼图重叠。

enter image description here

在其他情况下,可能仍需要调整这些间距,以确保不会出现重叠现象,例如:

title = plt.title('What slows down my computer')
title.set_ha("left")
plt.gca().axis("equal")
pie = plt.pie(total, startangle=0)
labels=["Trojans", "Viruses", "Too many open tabs", "The anti-virus software"]
plt.legend(pie[0],labels, bbox_to_anchor=(1,0.5), loc="center right", fontsize=10, 
           bbox_transform=plt.gcf().transFigure)
plt.subplots_adjust(left=0.0, bottom=0.1, right=0.45)

enter image description here

使用bbox_inches="tight"保存文件

有时候,我们对于保存的图像比在屏幕上看到的更感兴趣。这时,我们可以简单地将图例放置在图像边缘位置,例如:

enter image description here

但是,我们需要在使用savefig保存时添加bbox_inches="tight"参数。

plt.savefig("output.png", bbox_inches="tight")

这将创建一个更大的图形,紧密地包围画布的内容:

enter image description here

一种复杂的方法,允许将图例紧密地放置在图形内部,而不改变图形大小,这里提供了详细的解决方案:Creating figure with exact size and no padding (and legend outside the axes)

使用子图

另一种选择是使用子图来保留图例的空间。 在这种情况下,一个子图可以放置饼图,另一个子图则包含图例。 如下所示。

fig = plt.figure(4, figsize=(3,3))
ax = fig.add_subplot(211) 
total = [4,3,2,81]
labels = ["tough working conditions", "high risk of accident", 
              "harsh weather", "it's not allowed to watch DVDs"]
ax.set_title('What people know about oil rigs')
ax.axis("equal")
pie = ax.pie(total, startangle=0)
ax2 = fig.add_subplot(212)
ax2.axis("off") 
ax2.legend(pie[0],labels, loc="center")

enter image description here


最后,我找到了它 "bbox_inches="tight"" - Qinsi
2
非常感谢您提供这个精彩的答案,您减轻了我因matplotlib而产生的痛苦! - Will
1
太棒了!感谢您让我开心一整天,先生! - Stephan
你今天帮了我很多!你的一个回答包含了解决我10个matplotlib问题的方法! - Madhavi Jouhari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接