【问题标题】:add percent labels to three-level donut chart将百分比标签添加到三级圆环图
【发布时间】:2019-12-27 11:59:23
【问题描述】:

我想为我的三层甜甜圈图中的每个标签和图层添加百分比值。

以下代码适当地生成三层圆环图和图例。但是,它会弄乱百分比值的显示(请参阅此问题底部的输出图)。

堆栈溢出或其他地方的当前解决方案仅适用于将百分比值添加到饼图/甜甜圈图(例如:How do I use matplotlib autopct? ),但我的饼图/甜甜圈图有三个层/级别。我的代码如下:

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure()
fig.set_figheight(7)
fig.set_figwidth(22)

ax1 = fig.add_subplot(121)

first_labels = ["Bonjovi", "Superman", "Darius_royale", "Stargazer_1991_viz", "Obligatory_Vis1", "Gertrude", 'Trimbel', "Olio", "Iniwaka"]
first_sizes = [2000, 300, 200, 100, 100, 150, 40, 30, 700]

second_sizes = [1000, 200, 200, 400, 500, 40, 1, 1, 1000]

third_sizes = [500, 300, 400, 500, 400, 100, 5, 2, 800]

flatui = (sns.diverging_palette(20, 250, n=8))

bigger = plt.pie(first_sizes, colors=flatui, startangle=90, frame=True, radius = 1,
                 wedgeprops={'edgecolor':'k'}, autopct = '%1.1%%f')

smaller = plt.pie(second_sizes, colors=flatui, radius=0.9, startangle=90,
                 wedgeprops={'edgecolor':'k'}, autopct = '%1.1%%f')

smallest = plt.pie(third_sizes, colors=flatui, radius=0.8, startangle=90, 
                  wedgeprops={'edgecolor':'k'}, autopct = '%1.1%%f')

centre_circle = plt.Circle((0, 0), 0.7, color='white', linewidth=0)

plt.gca().add_artist(centre_circle)

# add legend to current ax:
plt.gca().legend(first_labels, loc='center right', bbox_to_anchor=(1,0,.4,1), frameon = True)

plt.show();

上面代码的结果如下:

有人可以指导我如何让百分比值在每个甜甜圈环中整齐地显示吗?

【问题讨论】:

  • 这能回答你的问题吗? How do I use matplotlib autopct?
  • 不幸的是,建议的解决方案仅在饼图/甜甜圈图有一层/级别时才有效。我在上面的圆环图中有三个级别。因此,该链接无法回答我的问题。
  • 此格式字符串'%1.1%%f' 似乎不正确。我猜应该是'%4.2f%%'(注意f的位置)。
  • 如果您要解决的问题是百分位数的位置,那么您正在寻找matplotlib.pie()pctdistance 参数。
  • 我得到了很好的视觉效果,pctdistances 对于每个饼图分别为 1、0.9 和 0.8。

标签: python matplotlib


【解决方案1】:

总结我的 cmets,这里是我得到更好图形输出的代码,我相信,你在寻找什么:

import matplotlib.pyplot as plt
import numpy as np


# Example function that you can call from pie(autopct=autopct)
def autopct(pct):
    if pct > 0.5:
        return f'{pct:.2f}%'
    else:
        return ''


fig = plt.figure()
fig.set_figheight(7)
fig.set_figwidth(22)

ax1 = fig.add_subplot(121)

first_labels = (
    'Bonjovi',
    'Superman',
    'Darius Royale',
    'Stargazer 1991 Viz',
    'Obligatory Vis1',
    'Gertrude',
    'Trimbel',
    'Olio',
    'Iniwaka'
)
first_sizes = (2000, 300, 200, 100, 100, 150, 40, 30, 700)
second_sizes = (1000, 200, 200, 400, 500, 40, 1, 1, 1000)
third_sizes = (500, 300, 400, 500, 400, 100, 5, 2, 800)

flatui = (sns.diverging_palette(20, 250, n=8))

bigger = plt.pie(
    first_sizes,
    colors=flatui,
    startangle=90,
    frame=True,
    radius=1,
    wedgeprops={'edgecolor':'k'},
#    autopct='%.2f%%',
    autopct=autopct,
    pctdistance=1
)

smaller = plt.pie(
    second_sizes,
    colors=flatui,
    radius=0.9,
    startangle=90,
    wedgeprops={'edgecolor':'k'},
#    autopct='%.2f%%',
    autopct=autopct,
    pctdistance=.9
)

smallest = plt.pie(
    third_sizes,
    colors=flatui,
    radius=0.8,
    startangle=90,
    wedgeprops={'edgecolor':'k'},
#    autopct='%.2f%%',
    autopct=autopct,
    pctdistance=.8
)

centre_circle = plt.Circle((0, 0), 0.7, color='white', linewidth=0)

plt.gca().add_artist(centre_circle)

# add legend to current ax:
plt.gca().legend(
    first_labels,
    loc='center right',
    bbox_to_anchor=(1,0,.4,1),
    frameon=True
)

plt.show()

您需要调整pctdistance,直到您对结果满意为止。

编辑:

经过一番研究,我写了这个更好的(恕我直言)版本:

import matplotlib.pyplot as plt


fig, ax = plt.subplots()
ax.axis('equal')

sizes = dict(
    first = (2000, 300, 200, 100, 100, 150, 40, 30, 700),
    second = (1000, 200, 200, 400, 500, 40, 1, 1, 1000),
    third = (500, 300, 400, 500, 400, 100, 5, 2, 800)
)

percentiles = dict(
    first = [x*100/sum(sizes['first']) for x in sizes['first']],
    second = [x*100/sum(sizes['second']) for x in sizes['second']],
    third = [x*100/sum(sizes['third']) for x in sizes['third']]
)

labels = dict(
    first = [f"{x:.2f}%" if x >.5 else '' for x in percentiles['first']],
    second = [f"{x:.2f}%" if x >.5 else '' for x in percentiles['second']],
    third = [f"{x:.2f}%" if x >.5 else '' for x in percentiles['third']]
)

width = 0.35
radius = 1.5

first, _ = ax.pie(
    sizes['first'],
    startangle=90,
    radius=radius,
    labeldistance=.9,
    labels=labels['first'],
    rotatelabels=True
)

second, _ = ax.pie(
    sizes['second'],
    radius=radius - width,
    startangle=90,
    labeldistance=.9,
    labels=labels['second'],
    rotatelabels=True
)

third, _ = ax.pie(
    sizes['third'],
    radius=radius - 2 * width,
    startangle=90,
    labeldistance=.9,
    labels=labels['third'],
    rotatelabels=True
)

plt.setp(first + second + third, width=width, edgecolor='white')

plt.show()

【讨论】:

  • 感谢您解释 pctdistance 修饰符,Accdias!几乎就在那里 - 但视觉效果还不是很理想!有些值有些重叠......有没有办法只显示那些大于某个百分比(例如:3% 或更高)的值或旋转您认为的标签内的值?
  • 您可以为autopct 传递一个函数,然后您可以让您的函数根据您想要的条件返回一个字符串。关于旋转标签,我想我们没有那个功能。我去看看说明书。
  • 您能否为您正在考虑的函数提供一个简单的代码示例?如果可以设定标准,我认为轮换是不必要的。提高视觉吸引力的一个简单解决方法是简单地将每个甜甜圈层的厚度增加到 0.2 个单位而不是 0.1 个单位。这让我可以更好地控制使用 pct 距离并将 % 值拟合到每个甜甜圈/级别的中心。
  • 查看示例here。我还找到了参数rotatelabels,但它似乎对生成的图形没有任何影响。
  • 这是非常有用的 accdias - 我会接受您的回答,并且可能会发布一个单独的问题,仅打印那些大于某个截止值的值。
猜你喜欢
  • 2017-11-27
  • 2021-07-17
  • 2018-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-25
相关资源
最近更新 更多