Python:从多维数据呈现图表

Python:从多维数据呈现图表,python,list,sorting,dictionary,multidimensional-array,Python,List,Sorting,Dictionary,Multidimensional Array,我正在编写一个脚本来从多维数组数据呈现饼图,并且正在努力使每个步骤保持同步 下面是我的代码,其中包含一些虚拟数据(动物类型),例如: def parse_data(chart): print("\n=====Chart Data=====") for a, b in chart.items(): # the dictionary "chart" has items - key:a value:b output = [] #

我正在编写一个脚本来从多维数组数据呈现饼图,并且正在努力使每个步骤保持同步

下面是我的代码,其中包含一些虚拟数据(动物类型),例如:

def parse_data(chart):
    print("\n=====Chart Data=====")
    for a, b in chart.items(): # the dictionary "chart" has items - key:a value:b
        output = [] # list of what to print to the console
        output.append(str(a)) # key:a - the name of the superset
        if type(b) is float: # if there are no subsets and the value is a float...
            output.append(': ' + str(b) + '%') # add that number (%) to the console output list
        elif type(b) is list: # else if there are subsets they'll be in a list
            for c in b:
                for d, e in c.items():
                    output.append('\n  ' + str(d) + ': ' + str(e) + '%')
        else: # if 'b' is neither a float nor a list
            print('Error: Data could not be parsed correctly.')
        print('\n' + ''.join(map(str, output))) # put the output list together and print it

chart_data = {
    "Mammal Group": [{"Hamster":23.1}, {"Yeti":16.4}],
    "Platypus": 14.2,
    "Reptile Group": [{"Snake":4.0}, {"Komodo Dragon":0.7}]
}

parse_data(chart_data)
控制台输出为:

=====Chart Data=====

Mammal Group
  Hamster: 23.1%
  Yeti: 16.4%

Platypus: 14.2%

Reptile Group
  Snake: 4.0%
  Komodo Dragon: 0.7%
到目前为止,一切看起来都很好。组/超集由内部切片表示,子集由外部切片表示。请注意,有些动物(鸭嘴兽)不属于一个群体,它们的名字旁边直接列出了一个百分比。其他动物是一些较大的组/超集的子集。下一步是获取该数据,并逐组将数据发送到要呈现的函数

这是一个模拟动画,我认为渲染的顺序是合乎逻辑的:超集,然后是该超集的子集,然后移动到下一个超集(如果有)。如果没有父超集(鸭嘴兽),请跳过对超集的渲染,让子集同时占据内部和外部区域)。最终图表将不会设置动画;这只是为了说明顺序

创建每个切片时,需要跟踪起始角度和结束角度。子集切片的角度与超集切片的角度不同。这需要以某种方式进行跟踪,以便在渲染集后,将角度标记放置在其末端,准备制作下一个切片


我已经让渲染函数工作了,但是试图一片一片地为它提供正确的数据让我发疯。如何有组织地提取
图表\u数据
,以提供给渲染功能?谢谢你的帮助

虽然其他人不太可能需要编写类似的代码,但由于我已经找到了解决方案,我不想让这个问题没有答案,所以我将尝试解释我的解决方案。任何好奇的人都可以继续阅读

我通过创建两个空列表来解决这个问题——一个用于“超集”内部切片,另一个用于“子集”外部切片,然后在图表数据迭代时填充它们。尽管子集切片始终是原始图表数据结构中的超集切片的子级,但渲染图表时不需要保留该结构

没有子子集的超集将同时添加到超级和子列表中,但这在最终的饼图中是不可见的。要理解“不可见”的含义,请想象模型图像中的蓝色切片实际上由一个内部片段和一个外部片段组成,一个接一个。如果饼图未经旋转,并以两条平行直线排列,它们仍会彼此对齐,因为它们具有相同的百分比

但是只有一个应该被标记,并且在外部区域有更多的文本空间。因此,不包含子集切片的超集切片将删除其名称标签,并将其设置为数据类型
None
。取而代之的是,这些名称标签被移动到每个相邻的子集切片。标记为
None
的切片将不会渲染,但位置标记将按该切片的百分比旋转。以实物模型图像为例,这就是允许从绿色超集切片的末尾移动到橙色超集切片的开头,而无需在蓝色切片上“绘制”不需要的第二个切片的原因。(将内部超集切片想象为放置在外部子集切片之上并覆盖外部子集切片。)

阅读本文的大多数人可能都知道,将
None
数据类型作为字典中的键不会多次起作用。例如,条目
“鸭嘴兽”:14.2
将导致
无:14.2
,该条目将被
“Jabberwock”:41.6
覆盖到
无:41.6
。因此,我决定先将字典
chart\u data
转换为列表,然后再将其格式化为图形

随着迭代的进行,子集切片的百分比将被汇总,以便它们的父超集组在大小上与它们匹配。(如果在两条平行轨道上布置,则尺寸表示宽度,如果在饼图中查看,则表示旋转角度。)

最后,我输入了一些代码来检查图表百分比加起来是否等于100

chart_data = {
    "Mammal Group": [{"Hamster":23.1}, {"Yeti":16.4}],
    "Platypus": 14.2,
    "Reptile Group": [{"Snake":4.0}, {"Komodo Dragon":0.7}],
    "Jabberwock" : 41.6
}

track_sup = []
track_sub = []

def dict_to_list(dict): # converts a dictionary to a list (nested dictionaries are untouched)
    new_list = []
    for key, value in dict.items():
        super_pair = [key, value]
        new_list.append(super_pair)
    return new_list

def format_data(dict_data):
    global track_sup
    global track_sub
    track_sup = []
    track_sub = []
    print('\n\n\n====== Formatting data ======')
    super_slices = dict_to_list(dict_data) # convert to list to allow more than one single super slice (their labels are type: None)
    chart_perc = 0.0 # for checking that the chart slices all add up to 100%
    i = 0
    while i < len(super_slices):
        tally = 0.0 # for adding up subset percentages to get each superset percentage
        is_single = True # supersets single by default
        super_slice = super_slices[i]
        slice_label = ''
        super_pair = []
        sub_pair = []
        if type(super_slice[1]) == list: # if [1] is a list, there are sub slices
            is_single = False # mark superset as containing multiple subsets
            slice_label = super_slice[0]
            sub_slices = super_slice[1]
            j = 0
            while j < len(sub_slices): # iterate sub slices to gather label names and percentages
                sub_slice = sub_slices[j]
                for k, v in sub_slice.items(): # in each dict, k is a label and v is a percentage
                    v = float(v)
                    tally = tally + v # count toward super slice (group) percentage
                    chart_perc = chart_perc + v # count toward chart total percentage
                    sub_pair = [k, v] # convert each key-value pair into a list
                    print(str(sub_pair[0]) + ' ' + str(sub_pair[1]) + ' %')
                    track_sub.append(sub_pair) # append this pair to final sub output list
                j = j + 1
            print('Group [' + slice_label + '] combined total is ' + str(tally) + ' % \n')
        elif type(super_slice[1]) == float: # this super slice (group) contains no sub slices
            slice_label = super_slice[0]
            tally = super_slice[1] # no sub slice percentages to add up
            chart_perc = chart_perc + super_slice[1] # count toward chart total percentage
            sub_pair = [slice_label, tally] # label drops to the sub slot as it only labels itself
            track_sub.append(sub_pair) # append this pair to final sub output list
            print(slice_label + ' ' + str(tally) + ' %  (Does not belong to a group)\n')
        else:
            print('Error: Could not format data.')
        
        if is_single == True:
            slice_label = None # label removed for each single slice - only the percentage is used (for spacing)
            
        super_pair = [slice_label, tally] # pair up each label name and super slice percentage in a list
        track_sup.append(super_pair) # append this pair to final super output list
        
        i = i + 1
        
    chart_perc = round(chart_perc, 6) # round to 6 decimal places
    short = 0.0
    if chart_perc == 100.0:
        print('______ Sum of all chart slices is 100 % ______\n')
    else:
        print('****** WARNING: Chart slices do not add up to 100 % ! ******')
        short = round(100.0 - chart_perc, 6)
        print('Sum of all chart slices is only ' + str(chart_perc) + ' %  (Falling short by ' + str(short) + ' %)\n')

format_data(chart_data)
print(track_sup)
print(track_sub)
track\u sup
track\u sub
是两个列表,其数据显示在最后两行输出中,实际用于绘制图表

====== Formatting data ======
Hamster 23.1 %
Yeti 16.4 %
Group [Mammal Group] combined total is 39.5 % 

Platypus 14.2 %  (Does not belong to a group)

Snake 4.0 %
Komodo Dragon 0.7 %
Group [Reptile Group] combined total is 4.7 % 

Jabberwock 41.6 %  (Does not belong to a group)

______ Sum of all chart slices is 100 % ______

[['Mammal Group', 39.5], [None, 14.2], ['Reptile Group', 4.7], [None, 41.6]]
[['Hamster', 23.1], ['Yeti', 16.4], ['Platypus', 14.2], ['Snake', 4.0], ['Komodo Dragon', 0.7], ['Jabberwock', 41.6]]