【问题标题】:Python: Rendering a chart from multidimensional dataPython:从多维数据渲染图表
【发布时间】:2021-02-16 20:16:37
【问题描述】:

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

这是我的代码,例如一些虚拟数据(动物类型):

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%

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

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

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

我已经让渲染功能正常工作,但试图逐片为其提供正确的数据让我抓狂。如何以有组织的方式提取chart_data 以提供给渲染功能?感谢您的帮助!

【问题讨论】:

    标签: python list sorting dictionary multidimensional-array


    【解决方案1】:

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

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

    没有子集的超集被添加到超级子列表中,但这在最终的饼图中是不可见的。要理解“不可见”的含义,想象模型图像中的蓝色切片实际上是由一个内段和外段组成,一个在另一个旁边。如果饼图展开并布置成两条平行的直线轨道,它们仍然会相互对齐,因为它们具有相同的百分比。

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

    大多数阅读本文的人可能都知道,将None 数据类型作为字典中的键不会多次起作用。例如,条目"Platypus" : 14.2 将导致None : 14.2,这将被"Jabberwock" : 41.6 覆盖为None : 41.6。因此,我决定先将字典 chart_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)
    

    以及由此产生的控制台输出:

    ====== 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]]
    

    track_suptrack_sub 是两个列表,其数据显示在最后两行输出中,实际用于渲染图表。

    【讨论】:

      猜你喜欢
      • 2012-04-06
      • 2017-08-14
      • 1970-01-01
      • 2019-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多