matplotlib 堆叠饼图-如何设置依赖于外部Piechart的内部Piechart标签

nvbavucw  于 2022-11-15  发布在  其他
关注(0)|答案(1)|浏览(140)

我有一个以百分比为标签的堆积饼图。外部饼图的标签与我希望的一样;但是,内部饼图的标签应该基于它福尔斯外部饼图下的位置。例如,在下图中,对于外部饼图的每种颜色,内部饼图的百分比标签的总和应该为100%。当前,对于红色外部饼图,内部饼图的百分比标签分别为11.0%、12.0% 7.0%,这是不考虑外部图表的百分比。我希望它们显示类似于35%、38%、27%的内容,外部饼图的绿色和黄色也是如此,其中内部图表标签取决于外部饼图的颜色。

这是一个可重现的例子

import pandas as pd
import numpy as np
import random
import matplotlib.pyplot as plt

options = ['RED','YELLOW','GREEN']
color_list1 = []
color_list2 = []

for i in np.arange(100):
    color1 = random.choice(options)
    color2 = random.choice(options)
    color_list1.append(color1)
    color_list2.append(color2)

test_df = pd.DataFrame(list(zip(color_list1, color_list2)), columns =['Outer_Color', 'Inner_Color'])

outer = pd.DataFrame(test_df.groupby('Outer_Color').size())
inner = pd.DataFrame(test_df.groupby(['Outer_Color', 'Inner_Color']).size())
inner_labels = inner.index.get_level_values(1)

my_pal = {"RED": "r", "YELLOW": "yellow", "GREEN":"g"}

fig, ax = plt.subplots(figsize=(14,7))
size = 0.3

ax.pie(outer.values.flatten(), radius=1,
#        labels=outer.index,
       autopct='%1.1f%%', pctdistance=0.85, # labeldistance=0.2,
       wedgeprops=dict(width=size, edgecolor='w'),
       colors=[my_pal[key] for key in outer.index])

ax.pie(inner.values.flatten(), radius=1-size, 
#        labels = inner_labels,
       autopct='%1.1f%%', pctdistance=0.7, # labeldistance=1.2,
       wedgeprops=dict(width=size, edgecolor='w'),
       colors=[my_pal[key] for key in inner_labels])

plt.show()
fnvucqvd

fnvucqvd1#

可以采用的一种方法是计算内部楔形块相对于外部楔形块的百分比,然后创建新标签,以便在执行ax.pie时通过。例如:

# Construct inner labels
    inner_str_label = []  # new labels storage
    n_inside = 3  # number of inner wedges per outer wedge
    for idx, outer_value in enumerate(outer.values.flatten()):
        # Get inner values for each outer wedge
        for inner_value in inner.values.flatten()[idx*n_inside:idx*n_inside+n_inside]:
            # format for only 1 decimal place
            new_label = f"{'{0:.1f}'.format(inner_value/outer_value*100)}%"
            inner_str_label.append(new_label)

现在,我们可以使用labels传递ax.pie中的新标签:

import pandas as pd
import numpy as np
import random
import matplotlib.pyplot as plt

if __name__ == '__main__':

    options = ['RED', 'YELLOW', 'GREEN']
    color_list1 = []
    color_list2 = []

    for i in np.arange(100):
        color1 = random.choice(options)
        color2 = random.choice(options)
        color_list1.append(color1)
        color_list2.append(color2)

    test_df = pd.DataFrame(list(zip(color_list1, color_list2)), columns =['Outer_Color', 'Inner_Color'])

    outer = pd.DataFrame(test_df.groupby('Outer_Color').size())
    inner = pd.DataFrame(test_df.groupby(['Outer_Color', 'Inner_Color']).size())

    my_pal = {"RED": "r", "YELLOW": "yellow", "GREEN": "g"}

    fig, ax = plt.subplots(figsize=(14, 7))
    size = 0.3

    ax.pie(outer.values.flatten(), radius=1,
           #        labels=outer.index,
           autopct='%1.1f%%', pctdistance=0.85,  # labeldistance=0.2,
           wedgeprops=dict(width=size, edgecolor='w'),
           colors=[my_pal[key] for key in outer.index])

    # Construct inner labels
    inner_str_label = []  # new labels storage
    n_inside = 3  # number of inner wedges per outer wedge
    for idx, outer_value in enumerate(outer.values.flatten()):
        # Get inner values for each outer wedge
        for inner_value in inner.values.flatten()[idx*n_inside:idx*n_inside+n_inside]:
            # format for only 1 decimal place
            new_label = f"{'{0:.1f}'.format(inner_value/outer_value*100)}%"
            inner_str_label.append(new_label)

    wedges, labels = ax.pie(inner.values.flatten(), radius=1-size, labels=inner_str_label, labeldistance=0.8,
                            wedgeprops=dict(width=size, edgecolor='w'),
                            colors=[my_pal[key] for key in inner.index.get_level_values(1)])

    # Fix inner label position
    for string_label in labels:
        string_label.update({"rotation": 0, "horizontalalignment": "center", "verticalalignment": "center"})

    plt.show()

请注意,这是假设每个外部楔形块都有相同数量的内部楔形块。如果内部楔形块的数量不规则,则方法类似,但您可以在列表中设置每个外部楔形块的内部楔形块数量:

# Construct inner labels
    inner_str_label = []  # new labels storage
    n_inside_list = [2, 3, 2]  # number of inner wedges per outer wedge
    for idx, outer_value in enumerate(outer.values.flatten()):
        # Get inner values for each outer wedge
        n_inside = n_inside_list[idx]
        for inner_value in inner.values.flatten()[idx*n_inside:idx*n_inside+n_inside]:
            # format for only 1 decimal place
            new_label = f"{'{0:.1f}'.format(inner_value/outer_value*100)}%"
            inner_str_label.append(new_label)

希望这对你有帮助-干杯!

相关问题