Создайте дерево иерархии json из двухколоночного фрейма данных (Python3) для визуального сворачиваемого дерева d3 - PullRequest
0 голосов
/ 19 февраля 2019

У меня есть датафрейм с двумя столбцами: Employee и Reports_to.Каждый сотрудник подчиняется кому-то, вплоть до генерального директора.Я хотел бы преобразовать это в файл json, который может быть использован свертываемым деревом d3 (согласно этой замечательной ссылке: d3 свертываемое дерево ).Сделал бы для большой организационной диаграммы, которая может быть обновлена ​​с небольшим / никаким ручным усилием.

Collapsible org chart

Мне удалось преобразовать df в правильный формат json, как показано в простом примере ниже.Однако я сделал это очень болезненно в Excel, а затем скопировал и вставил .append строки в Jupyter (!). Вот мой вопрос: существует ли в Python3 элегантный способ преобразования df с двумя столбцами в требуемый dict?

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': []})

Вот результирующий dict, требуемый деревом 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.

1 Ответ

0 голосов
/ 04 марта 2019

Я нашел способ, благодаря Джонатану Юнис отсюда создать дерево .

#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)

... и следуйте инструкциям, чтобы отобразить дерево d3 в вашем браузере согласно ОП.Это должно дать вам дерево, как показано в ОП.Это падает, если дерево слишком большое, но вы можете создать одну основную ветвь за раз и объединить их в одно дерево в конце (хотя это не легко).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...