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

6
在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}")。

但是当图包含多个不相连的组件时,如何指定多个根节点呢?也就是一片森林中的多棵树。

如果不提供根参数,将会得到以下绘图:

enter image description here

从可视化效果上看,它已经正确选择了10棵树的根节点,但对于12棵树,它选择了真正根节点的子节点作为中心(因此一些分支相对于其他分支似乎更浅)。

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


你可以看一下这个纯networkx解决方案:https://dev59.com/ul0b5IYBdhLWcg3wIOB9#29597209 需要一些适应,但我认为很简单。 - Joel
1个回答

5
我认为使用graphviz的twopi布局没有单个图形的方法来实现这一点。Twopi通常可以很好地设置每个子图的根节点,因为如文档中所述,它会随机选择距离叶节点最远的节点之一作为根节点,所以在只有一个根节点的情况下,这应该导致预期的拓扑结构排列。但是,如果不是这种情况,并且您想要为每个子图手动设置根节点,则我的方法是通过迭代连接组分子图中的图形,并将每个组件绘制到subplot图中的单独轴中,为每个创建自定义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)


enter image description here


2
谢谢,yatu - 这确实是我的解决方法,但我想保持图形之间边缘的相对长度(当它们同时绘制时保持不变,但如果树具有不同的“深度”,则在单独绘制时它们将以不同的比例缩放,如您的图所示)。但我意识到我可以使用 subplots(sharex=True, sharey=True) 强制它们保持相同的比例。 - iacob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接