【问题标题】:Python - Legend overlaps with the pie chartPython - 图例与饼图重叠
【发布时间】:2017-09-02 11:44:18
【问题描述】:

在 python 中使用 matplotlib。图例与我的饼图重叠。尝试了“loc”的各种选项,例如“best”,1,2,3...但无济于事。关于如何准确提及图例位置(例如从饼图边界提供填充)或至少确保它不重叠的任何建议?

【问题讨论】:

    标签: python matplotlib charts


    【解决方案1】:

    简短的回答是:您可以使用plt.legend 的参数locbbox_to_anchor 以及另外的bbox_transformmode,将图例定位在轴或图形中。


    长版:

    第 1 步:确保需要图例。

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

    如果情节确实不能没有图例,请继续第 2 步。

    第 2 步:确保需要饼图。

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

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

    放置图例

    plt.legend() 有两个主要参数来确定图例的位置。最重要且本身就足够了的是loc 参数。
    例如。 plt.legend(loc="upper left") 放置图例,使其位于边界框的左上角。如果未指定其他参数,则此边界框将是整个轴。

    但是,我们可以使用bbox_to_anchor 参数指定我们自己的边界框。如果给 bbox_to_anchor 一个 2 元组,例如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)是图的右下角。由于轴和图形边缘之间的默认间距,这足以放置图例,使其不与饼图重叠。

    在其他情况下,可能仍需要调整这些间距,以便看不到重叠,例如

    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)
    

    bbox_inches="tight"保存文件

    现在,我们可能对保存的图形比对屏幕上显示的图形更感兴趣。然后我们可以简单地将图例定位在图形的边缘,就像这样

    但随后使用bbox_inches="tight" 将其保存到savefig

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

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

    这里介绍了一种复杂的方法,它允许将图例紧紧地放置在图形内,而不改变图形大小: 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")
    

    【讨论】:

    • 终于找到了"bbox_inches="tight""
    • 感谢您的精彩回答,您已经在一定程度上减少了我的 matplotlib 引起的痛苦!
    • 很棒的答案!谢谢你让我开心,先生!
    • 你今天帮了我很多忙!您的 1 个答案包含我的 10 个 matplotlib 问题的解决方案!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-09
    • 1970-01-01
    相关资源
    最近更新 更多