【问题标题】:Create json hierarchy tree from two-column dataframe (Python3) for d3 collapsible tree visual从两列数据框(Python3)为 d3 可折叠树视觉创建 json 层次结构树
【发布时间】:2019-02-18 22:17:59
【问题描述】:

我有一个包含两列的数据框:Employee 和 Reports_to。每个员工都向某人报告,一直到首席执行官。我想把它转换成一个 json 文件,可以被可折叠的 d3 树使用(根据这个很棒的链接:d3 collapsible tree)。将制作一个出色的组织结构图,只需很少/无需手动操作即可保持最新。

我已经能够将 df 转换为正确的 json 格式,如下面的简单示例所示。但是,我在 Excel 中非常痛苦地执行此操作,然后将 .append 字符串复制并粘贴到 Jupyter (!) 中。 这是我的问题:在 Python3 中是否有一种优雅的方式将 2 列 df 转换为所需的字典?

import numpy as np
import pandas as pd
import json

#_Lx refers to the level in the organisation, where Jackie_L1 is the CEO
df = pd.DataFrame(np.array([
['Jo_L3','Jane_L2'],
['Jon_L3','Jane_L2'],
['James_L3','Jerry_L2'],
['Joan_L3','Jerry_L2'],
['Jane_L2','Jackie_L1'],
['Jerry_L2','Jackie_L1'],
['Jill_L2','Jackie_L1']]))
df.columns = ['Employee','Reports_to']
df 

Employee    Reports_to
Jo_L3       Jane_L2
Jon_L3      Jane_L2
James_L3    Jerry_L2
Joan_L3     Jerry_L2
Jane_L2     Jackie_L1
Jerry_L2    Jackie_L1
Jill_L2     Jackie_L1

#start with the root node and work over to the right (down the organisation) to provide the required json:
tree = {'parent': 'null', 'name': 'Jackie_L1', 'edge_name': 'Jackie_L1', 'children': []}

tree['children'].append({'parent': 'Jackie_L1', 'name': 'Jane_L2', 'edge_name': 'Jane_L2', 'children': []})
tree['children'].append({'parent': 'Jackie_L1', 'name': 'Jerry_L2', 'edge_name': 'Jerry_L2', 'children': []})
tree['children'].append({'parent': 'Jackie_L1', 'name': 'Jill_L2', 'edge_name': 'Jill_L2', 'children': []})

tree['children'][0]['children'].append({'parent': 'Jane_L2', 'name': 'Jo_L3', 'edge_name': 'Jo_L3', 'children': []})
tree['children'][0]['children'].append({'parent': 'Jane_L2', 'name': 'Jon_L3', 'edge_name': 'Jon_L3', 'children': []})
tree['children'][1]['children'].append({'parent': 'Jerry_L2', 'name': 'James_L3', 'edge_name': 'James_L3', 'children': []})
tree['children'][1]['children'].append({'parent': 'Jerry_L2', 'name': 'Joan_L3', 'edge_name': 'Joan_L3', 'children': []})

这是 d3 树所需的结果字典:

{'parent': 'null',
 'name': 'Jackie_L1',
 'edge_name': 'Jackie_L1',
 'children': [{'parent': 'Jackie_L1',
   'name': 'Jane_L2',
   'edge_name': 'Jane_L2',
   'children': [{'parent': 'Jane_L2',
     'name': 'Jo_L3',
     'edge_name': 'Jo_L3',
     'children': []},
    {'parent': 'Jane_L2',
     'name': 'Jon_L3',
     'edge_name': 'Jon_L3',
     'children': []}]},
  {'parent': 'Jackie_L1',
   'name': 'Jerry_L2',
   'edge_name': 'Jerry_L2',
   'children': [{'parent': 'Jerry_L2',
     'name': 'James_L3',
     'edge_name': 'James_L3',
     'children': []},
    {'parent': 'Jerry_L2',
     'name': 'Joan_L3',
     'edge_name': 'Joan_L3',
     'children': []}]},
  {'parent': 'Jackie_L1',
   'name': 'Jill_L2',
   'edge_name': 'Jill_L2',
   'children': []}]}

我将tree 转换成这样的 json 文件:

with open('C:/Python37/input_graph_tree.json', 'w') as outfile:
    json.dump(tree, outfile)

在桌面上运行可折叠树的说明在上面的链接中,尽管您需要使用python -m http.server 8080 来启动它,而不是python -m SimpleHTTPServer 8080

【问题讨论】:

    标签: json python-3.x dictionary tree


    【解决方案1】:

    感谢来自create tree 的 Jonathan Eunice,我找到了一种方法。

    #using the df example above, add a row for the top person:
    lastrow = len(df)
    df.loc[lastrow] = np.nan
    df.loc[lastrow, 'Employee'] = 'Jackie_L1'
    df.loc[lastrow, 'Reports_to'] = '' #top person does not report to anyone
    
    #create a new column called eid that is a copy of Employee (to make the 'buildtree' function below work):
    df['eid'] = df['Employee']
    df = df[['eid', 'Employee', 'Reports_to']] #get the order right
    
    #then run this
    from pprint import pprint
    from collections import defaultdict
    
    def show_val(title, val):
        sep = '-' * len(title)
        print ("\n{0}\n{1}\n{2}\n".format(sep, title, sep))
        pprint(val)
    
    def buildtree(t=None, parent_eid=''):
        """
        Given a parents lookup structure, construct
        a data hierarchy.
        """
        parent = parents.get(parent_eid, None)
        if parent is None:
            return t
        for eid, name, mid in parent:
            if mid == '': report = {'parent': 'null', 'name': name, 'edge_name': name }
            else : report = {'parent': mid, 'name': name, 'edge_name': name }
            if t is None:
                t = report
            else:
                reports = t.setdefault('children', [])
                reports.append(report)
            buildtree(report, eid)
        return t
    
    people = list(df.itertuples(index=False, name=None))
    
    parents = defaultdict(list)
    for p in people:
        parents[p[2]].append(p)
    tree = buildtree()
    show_val("data", tree)
    
    #which gives you:
    ----
    data
    ----
    
    {'children': [{'children': [{'edge_name': 'Jo_L3',
                                 'name': 'Jo_L3',
                                 'parent': 'Jane_L2'},
                                {'edge_name': 'Jon_L3',
                                 'name': 'Jon_L3',
                                 'parent': 'Jane_L2'}],
                   'edge_name': 'Jane_L2',
                   'name': 'Jane_L2',
                   'parent': 'Jackie_L1'},
                  {'children': [{'edge_name': 'James_L3',
                                 'name': 'James_L3',
                                 'parent': 'Jerry_L2'},
                                {'edge_name': 'Joan_L3',
                                 'name': 'Joan_L3',
                                 'parent': 'Jerry_L2'}],
                   'edge_name': 'Jerry_L2',
                   'name': 'Jerry_L2',
                   'parent': 'Jackie_L1'},
                  {'edge_name': 'Jill_L2',
                   'name': 'Jill_L2',
                   'parent': 'Jackie_L1'}],
     'edge_name': 'Jackie_L1',
     'name': 'Jackie_L1',
     'parent': 'null'}
    
    #then write to json:
    with open('C:/Python37/input_graph_tree.json', 'w') as outfile:
        json.dump(tree, outfile)
    

    ...并按照说明按照 OP 在浏览器中显示 d3 树。这应该为您提供如 OP 中所示的树。如果树太大,这会倒下,但您可以一次创建一个主分支,并在最后将它们组合成一棵树(虽然不容易)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-02
      • 2015-03-10
      • 2012-08-16
      • 2017-04-18
      • 1970-01-01
      • 2011-11-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多