Ответ 1
Вы можете сделать это в три этапа:
- Рекурсивно построить вложенный словарь, который представляет дерево, возвращаемое методом Scipy
to_tree
. - Перейдите через вложенный словарь, чтобы пометить каждый внутренний node листами в его поддереве.
-
dump
полученный вложенный словарь в JSON и загрузить в d3.
Построить вложенный словарь, представляющий дендрограмму
Для первого шага важно вызвать to_tree
с помощью rd=False
, чтобы возвращался корень дендрограммы. Из этого корня вы можете построить вложенный словарь следующим образом:
# Create a nested dictionary from the ClusterNode returned by SciPy
def add_node(node, parent ):
# First create the new node and append it to its parent children
newNode = dict( node_id=node.id, children=[] )
parent["children"].append( newNode )
# Recursively add the current node children
if node.left: add_node( node.left, newNode )
if node.right: add_node( node.right, newNode )
T = scipy.cluster.hierarchy.to_tree( clusters , rd=False )
d3Dendro = dict(children=[], name="Root1")
add_node( T, d3Dendro )
# Output: => {'name': 'Root1', 'children': [{'node_id': 10, 'children': [{'node_id': 1, 'children': []}, {'node_id': 9, 'children': [{'node_id': 6, 'children': [{'node_id': 0, 'children': []}, {'node_id': 2, 'children': []}]}, {'node_id': 8, 'children': [{'node_id': 5, 'children': []}, {'node_id': 7, 'children': [{'node_id': 3, 'children': []}, {'node_id': 4, 'children': []}]}]}]}]}]}
Основная идея - начать с node не в дендрограмме, которая будет служить корнем всей дендрограммы. Затем мы рекурсивно добавляем левого и правого детей в этот словарь, пока не дойдем до листьев. На данный момент у нас нет меток для узлов, поэтому я просто помещаю узлы их идентификатором clusterNode.
Обозначьте дендрограмму
Далее, нам нужно использовать node_ids для обозначения дендрограммы. Комментарии должны быть достаточными для объяснения того, как это работает.
# Label each node with the names of each leaf in its subtree
def label_tree( n ):
# If the node is a leaf, then we have its name
if len(n["children"]) == 0:
leafNames = [ id2name[n["node_id"]] ]
# If not, flatten all the leaves in the node subtree
else:
leafNames = reduce(lambda ls, c: ls + label_tree(c), n["children"], [])
# Delete the node id since we don't need it anymore and
# it makes for cleaner JSON
del n["node_id"]
# Labeling convention: "-"-separated leaf names
n["name"] = name = "-".join(sorted(map(str, leafNames)))
return leafNames
label_tree( d3Dendro["children"][0] )
Дамп для JSON и загрузка в D3
Наконец, после того, как дендрограмма была помечена, нам просто нужно вывести ее в JSON и загрузить в D3. Я просто вставляю код Python, чтобы свалить его на JSON здесь для полноты.
# Output to JSON
json.dump(d3Dendro, open("d3-dendrogram.json", "w"), sort_keys=True, indent=4)
Выход
Я создал версии Dendrogram из Scipy и D3 ниже. Для версии D3 я просто подключил файл JSON, который я выводил ('d3-dendrogram.json'
), в этот Gist.
SciPy dendrogram
D3 dendrogram