无法在保留节点属性时生成树格式的网络数据

2024-04-18 09:37:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图生成一个可视化数据沿袭的网络图(集群图,如this)。请记住,我对NetworkX库非常陌生,下面的代码可能远不是最佳的。在

我的数据由两个Pandas数据帧组成:

  • df_objs:这个df包含一个UUID和不同项的名称(这些项将成为节点)
  • df_calls:这个df包含一个调用和被调用的UUID(这些UUID是对df_objs中项目的UUID的引用)。在

下面是初始化有向图并创建节点的步骤:

import networkx as nx
objs = df_objs.set_index('uuid').to_dict(orient='index')
g = nx.DiGraph()
for obj_id, obj_attrs in objs.items():
    g.add_node(obj_id, attr_dict=obj_attrs)

要生成边:

^{pr2}$

接下来,我想知道使用UUID的单个项目的沿袭:

g_tree = nx.DiGraph(nx.bfs_edges(g, 'f6e214b1bba34a01bd0c18f232d6aee2', reverse=True))

到目前为止还不错。最后一步是生成JSON图,以便将生成的JSON文件馈送到D3.js,以便执行可视化:

# Create the JSON data structure
from networkx.readwrite import json_graph
data = json_graph.tree_data(g_tree, root='f6e214b1bba34a01bd0c18f232d6aee2')
# Write the tree to a JSON file
import json
with open('./tree.json', 'w') as f:
    json.dump(data, f)

但是,上面所有的工作都是这样,而不是节点名,而是JSON数据中的UUID,因为在调用nx.bfs_edges()时节点属性被删除了。在

示例:

Tree example

没问题(至少我是这么想的);我将用g中的属性更新g_tree中的节点。在

obj_names = nx.get_node_attributes(g, 'name')
for obj_id, obj_name in obj_names.items():
    try:
        g_tree[obj_id]['name'] = obj_name
    except Exception:
        pass

注意:我不能使用set_node_attributes(),因为g包含的节点多于g_tree,这会导致KeyError。在

如果我再次尝试生成JSON数据:

data = json_graph.tree_data(g_tree, root='f6e214b1bba34a01bd0c18f232d6aee2')

它将抛出错误:

TypeError: G is not a tree.

这是由于number of nodes != number of edges + 1。在

在设置属性之前,节点数为81,边数为80。设置属性后,边数增加到120(节点数保持不变)。在

好吧,关于我的问题:

  1. 我是不是走了很长的路?有没有一种更短/更好/更快的方法来产生同样的结果?在
  2. 当我只设置节点的属性时,是什么导致边数增加?在
  3. 在尝试生成树时,有没有方法保留节点属性?在

Tags: 数据nameimportidjsontreeobjdf
1条回答
网友
1楼 · 发布于 2024-04-18 09:37:16

根据关于dict G[node]warning in the docs

Do not change the returned dict – it is part of the graph data structure and direct manipulation may leave the graph in an inconsistent state.

因此,对g_tree[obj_id]的赋值是否定的:

g_tree[obj_id]['name'] = obj_name

而是使用^{}修改属性:

^{pr2}$

另外,一旦有了g_tree,就可以使用

In [220]: g_tree.nodes()
Out[220]: ['A', 'C', 'B']

然后你可以用

for obj_id in g_tree.nodes():
    g_tree.node[obj_id] = g.node[obj_id]

将属性从g复制到g_tree。在


import json
import pandas as pd
import networkx as nx
from networkx.readwrite import json_graph

df_objs = pd.DataFrame({'uuid':list('ABCD'), 'name':['foo','bar','baz','quux']})
df_calls = pd.DataFrame({'calling':['A','A'], 'called':['B','C']})
objs = df_objs.set_index('uuid').to_dict(orient='index')
g = nx.DiGraph()
g.add_nodes_from(objs.items())
g.add_edges_from(df_calls[['calling','called']].drop_duplicates().values)

g_tree = nx.DiGraph(nx.bfs_edges(g, 'A'))

for obj_id in g_tree.nodes():
    g_tree.node[obj_id] = g.node[obj_id]

print(g_tree.nodes(data=True))
# [('A', {'name': 'foo'}), ('C', {'name': 'baz'}), ('B', {'name': 'bar'})]

data = json_graph.tree_data(g_tree, root='A')
print(json.dumps(data))
# {"children": [{"name": "baz", "id": "C"}, {"name": "bar", "id": "B"}], 
#  "name": "foo", "id": "A"}

相关问题 更多 >