首页 > 解决方案 > Networkx:如何为一次绘制多棵树指定多个根?

问题描述

在 networkx 中有一个使用径向布局(graphviz 的“twopi”)绘制树的功能:

import pydot
from networkx.drawing.nx_pydot import graphviz_layout

pos = graphviz_layout(G, prog='twopi', root=root, args='')

可以使用参数指定根节点root(在后台添加到 args 作为args += f" -Groot={root}")。

但是,当图形包含多个断开连接的组件时,如何指定多个根呢?即树木的森林。

我在不提供 root 参数的情况下得到以下图:

在此处输入图像描述

正如您在视觉上看到的那样,虽然它为 10 棵树正确选择了真正的根节点,但对于 12 棵树,它选择了真正根节点的一个节点作为中心(因此,相对于其他分支)。

如何手动指定多棵树的根?

标签: pythonnetworkxgraphviz

解决方案


我认为没有办法在带有graphviz的twopi布局的单个图中做到这一点。Twopi 通常应该在设置每个子图的根节点方面做得很好,因为如文档中所述,它会随机选择离叶节点最远的节点之一作为根,所以在有单个根的情况下节点,这应该导致预期的拓扑排列。虽然如果不是这种情况,并且您想手动设置每个子图的根,但我解决此问题的方法是迭代连接的组件子图,并将每个组件绘制到子图中的单独轴中,为每个人创建一个自定义graphviz_layout

使用以下示例图可以做到这一点:

from matplotlib import pyplot as plt
import pygraphviz
from networkx.drawing.nx_agraph import graphviz_layout

result_set = {('plant','tree'), ('tree','oak'), ('flower', 'rose'), ('flower','daisy'), ('plant','flower'), ('tree','pine'), ('plant','roots'), ('animal','fish'),('animal','bird'), ('bird','robin'), ('bird','falcon'), ('animal', 'homo'),('homo','homo-sapiens'), ('animal','reptile'), ('reptile','snake'),('fungi','mushroom'), ('fungi','mold'), ('fungi','toadstool'),('reptile','crocodile'), ('mushroom','Portabello'), ('mushroom','Shiitake'),('pine','roig'),('pine','pinyer'), ('tree','eucaliptus'),('rose','Floribunda'),('rose','grandiflora')}
G=nx.from_edgelist(result_set, create_using=nx.DiGraph)

为了迭代现有的子图,我们必须将当前图的副本创建为无向图(如果它还不是无向图),并使用以下命令创建子图列表nx.connected_component_subgraphs

UG = G.to_undirected()
subgraphs = list(nx.connected_component_subgraphs(UG))

假设我们知道我们希望不同组件的根节点是节点'plant''animal'并且'mushroom',我们现在可以创建一组子图,并遍历各个轴,以及子图对象和根列表(确保它们的顺序相同),为每个设置相应根节点的子图创建一个新布局:

n_cols = 2
roots = ['plant','animal','mushroom']
fig, axes = plt.subplots(nrows=int(np.ceil(len(subgraphs)/n_cols)), 
                         ncols=n_cols, 
                         figsize=(15,10))
plt.box(False)

for subgraph, root, ax in zip(subgraphs, roots, axes.flatten()):
    pos = graphviz_layout(G,  prog='twopi', args=f"-Groot={root}")
    nx.draw(subgraph, pos=pos, with_labels=True, 
            node_color='lightblue', node_size=500, ax=ax)


在此处输入图像描述


推荐阅读