Подтвердить что ты не робот

Библиотека Python для создания древовидных графиков из вложенных объектов Python (dicts)

Кто-нибудь знает о каких-либо библиотеках Python, которые позволяют вам просто и быстро передавать объект, вложенный в произвольные уровни, например, в дерево диктовок в соответствии с тем, что вы найдете в этой сущности, и можно выложить выполнимый файл графа дерева?

Простота является ключевым моментом здесь, так как я должен иметь возможность работать с людьми, которые не являются технически мыслящими.

Под деревом графов я подразумеваю что-то вроде следующего: я мог бы передать ему вложенный словарь значений, а затем создать древовидную структуру:


(источник: rubyforge.org)

4b9b3361

Ответ 1

поэтому библиотека, которую я рекомендую и использую для моего фрагмента кода в этом ответе, не является библиотекой python, но это удобная для python библиотека, под которой я подразумеваю, что код, использующий эту библиотеку, можно вставить в модуль python для обработки данные, и этот внешний код будет подключаться к существующему питонному коду на обоих концах, т.е. как входному, так и выходному, и я подозреваю, хотя, конечно, я не знаю, что все это на самом деле означает критерий "библиотека python". Поэтому, если вы пишете веб-приложение, этот код будет на стороне клиента. Другими словами, эта библиотека не является питоном, но работает с python.

  • его вход (почти) raw python dicts, а более конкретно json.load(a_python_dict) возвращает массив или объект json, формат, который, конечно, может распознать эта библиотека javascript; и

  • формат вывода - это либо HTML, либо SVG, а не объекты в некоторых языковой формат

Вы можете использовать d3.js. Он имеет класс специально для рендеринга деревьев:

var tree = d3.layout.tree().size([h, w]);

В папке примеров в источнике d3 также есть несколько примеров деревьев (рабочий код), которые вы можете клонировать/загружать из приведенной выше ссылки i.

Поскольку d3 является javascript-библиотекой, ее собственный формат данных - JSON.

Базовая структура представляет собой вложенный словарь, каждый словарь, представляющий единственный node с двумя значениями, имя node и его дочерние элементы (хранящиеся в массиве), с ключом имена и дети, соответственно:

{"name": "a_root_node", "children": ["B", "C"]}

и, конечно, просто конвертировать между словарями python и JSON:

>>> d = {"name": 'A', "children": ['B', 'C']}
>>> import json as JSON
>>> dj = JSON.dumps(d)
>>> dj
    '{"name": "A", "children": ["B", "C"]}'

Здесь представлено представление словаря на языке python большего дерева (десяток или около того узлов), которые я преобразовал в json, как указано выше, а затем представлен в d3 как дерево, показанное на изображении ниже:

tree = {'name': 'root', 'children': [{'name': 'node 2', 'children': 
       [{'name': 'node 4', 'children': [{'name': 'node 10', 'size': 7500}, 
       {'name': 'node 11', 'size': 12000}]}, {'name': 'node 5', 'children': 
       [{'name': 'node 12', 'children': [{'name': 'node 16', 'size': 10000}, 
       {'name': 'node 17', 'size': 12000}]}, {'name': 'node 13', 'size': 5000}]}]}, 
       {'name': 'node 3', 'children': [{'name': 'node 6', 'children': 
       [{'name': 'node 14', 'size': 8000}, {'name': 'node 15', 'size': 9000}]}, 
       {'name': 'node 7', 'children': [{'name': 'node 8', 'size': 10000}, 
       {'name': 'node 9', 'size': 12000}]}]}]}

tree represented as python dictionary rendered in d3:

Примечание: d3 отображается в браузере; изображение выше - всего лишь снимок экрана моего окна браузера.

Ответ 2

Я не уверен, что это совсем то, что вы имеете в виду, но это первое, что приходит на ум.

blockdiag в основном предназначен для использования в качестве автономного файлового процессора, аналогичного Graphviz (для которого существует интерфейс Python). Он принимает текстовый файл как ввод с простым синтаксисом с отбрасыванием мертвой точки и создает изображения как выходные данные.

Вы должны иметь возможность написать простую прокладку для вывода своей рекурсивной структуры dict, отформатированной для ввода в автономный blockdiag script, или импортировать необходимые внутренности пакета blockdiag и напрямую управлять выходом.

Если это звучит многообещающе, я посмотрю, могу ли я поднять код примера.

EDIT Пример кода:

def print_blockdiag(tree, parent=None):
    if not parent: print('blockdiag { orientation = portrait')
    for key in tree:
        if parent: print('   {} -> {};'.format(parent, key))
        print_blockdiag(tree[key], key)
    if not parent: print('}')

Это выведет файл, который может прочитать blockdiag.

Ответ 3

Я искал похожую проблему: печатать ключи dict с вложенными dicts, где структура ключей очень периодическая. Поэтому я написал рекурсивную функцию, которая печатает ключи каждого и каждого вложенного, , но для отдельной ветки.

Надеюсь, что следующий фрагмент кода поможет другим людям:

from itertools import zip_longest

def dictPrintKeysTopBranch(dic):
    #track recursive depth
    depth=dictPrintKeysTopBranch.data.get('depth',-1)+1;
    dictPrintKeysTopBranch.data['depth']=depth;

    #accumalte keys from nested dicts
    if type(dic) is type(dict()):
        listKeys=sorted(list(dic.keys()));

        #save keys of current depth
        dictPrintKeysTopBranch.data['listKeysDepth{}'.format(depth)]=listKeys;

        #repeat for top branch
        dictPrintKeysTopBranch(dic[listKeys[0]]);

    #print accumalated list of keys
    else: 
        #pad lists 
        lists=[];
        maxlen=[];
        for d in range(depth):
            l=dictPrintKeysTopBranch.data['listKeysDepth{}'.format(d)];
            lists.append(l);

            lens = [len(s) for s in l];
            maxlen.append(max(lens)+1);

        i=-1;
        for zipped in zip_longest(*lists, fillvalue=' '):
            i=i+1;
            #print(x)
            row = '';
            j=-1;
            for z in zipped:
                j=j+1;
                if i==0:
                    row = row+ ((' {: <'+str(maxlen[j])+'} -->\\').format(z));
                else :
                    row = row+ ((' {: <'+str(maxlen[j])+'}    |').format(z));
            print(row.strip('\\|->'));

    dictPrintKeysTopBranch.data={};
dictPrintKeysTopBranch.data={};

Вот пример:

mydict = { 'topLv':{'secLv':{'thirdLv':{'item1':42,'item2':'foo'}}}, 
           'topLvItem':[1,2,3], 
           'topLvOther':{'notPrinted':':('}
         }
dictPrintKeysTopBranch(mydict)

Вывод:

topLv       -->\ secLv  -->\ thirdLv  -->\ item1  
topLvItem      |           |             | item2     
topLvOther     |           |             |         

Ответ 4

В зависимости от того, что вам нужно, но если вам нужно только для просмотра содержимого, вы можете использовать онлайн-инструмент для этого - "Форматировать форматирование питона и viewer" может отображать dict как дерево.