Networkx:如何为一次绘制多棵树指定多个根?

uke*_*emi 6 python graphviz networkx

在 networkx 中有一个函数可以使用径向布局(graphviz 的“twopi”)绘制树:

import pydot
from networkx.drawing.nx_pydot import graphviz_layout

pos = graphviz_layout(G, prog='twopi', root=root, args='')
Run Code Online (Sandbox Code Playgroud)

可以使用参数指定根节点root(它被添加到引擎盖下的 args 中args += f" -Groot={root}")。

但是,当图形由多个断开连接的组件组成时,如何指定多个根?即一片树林。

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

在此处输入图片说明

正如你在视觉上看到的,虽然它正确地为 10 棵树选择了真正的根节点,但它为 12 选择了真正根节点的一个孩子作为中心(因此一些分支看起来比实际更浅,相对于其他分支)。

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

yat*_*atu 5

我认为没有办法在具有 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)
Run Code Online (Sandbox Code Playgroud)

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

UG = G.to_undirected()
subgraphs = list(nx.connected_component_subgraphs(UG))
Run Code Online (Sandbox Code Playgroud)

假设我们知道我们希望不同组件的根节点成为节点'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)
Run Code Online (Sandbox Code Playgroud)


在此处输入图片说明

  • 谢谢,yatu - 这确实是我的解决方案,但我想保持图形之间边缘的相对长度(当它们同时绘制时保持不变,但如果树有不同的“深度”,它们在单独绘制时会以不同的方式缩放,如图所示)。但我意识到我可以强迫它们通过“subplots(sharex=True, sharey=True)”保持相同的规模。 (2认同)