已编辑
我真的需要Networkx /图形专家的帮助。
让我们说我有以下数据框,我想将这些数据框转换为图形。然后,我想根据描述和优先级属性将两个图与相应的节点映射。
df1
[[79 44 24 67 53 90 0 57 74 86]
[47 17 24 81 16 12 22 52 63 70]
[17 94 71 76 23 66 76 59 77 19]
[17 43 12 90 27 28 27 89 39 20]
[22 49 38 49 56 70 77 40 71 13]
[29 73 2 45 30 2 88 65 65 88]
[79 15 31 44 19 2 74 4 7 35]
[89 67 76 66 4 14 63 29 90 6]
[86 51 61 17 79 78 64 67 33 63]
[45 16 30 93 75 42 86 93 63 84]]
[[False False False False False False False False False False]
[False False False False False False False False False False]
[ True False False False False False False False False True]
[ True False True False True True True False False True]
[ True False True False False False False False False True]
[ True False True True True True False False False False]
[False True True True True True False True True True]
[False True False True True True True True False True]
[False True True True True True True True True True]
[ True True True False True True True False True True]]
df2
From description To priority
10 Start 20, 50 1
20 Left 40 2
50 Bottom 40 2
40 End - 1
我刚刚转换了两个数据框并创建了一个图形(g1和g2)。
然后我仅尝试根据节点的描述和优先级来匹配节点。例如From description To priority
60 Start 70,80 1
70 Left 80, 90 2
80 Left 100 2
90 Bottom 100 2
100 End - 1
,而不是10/60, 40/100, 50/90
。 20/70, 20/80, and 70/80
有三个条件要映射,这不是我想要的。因为我只想映射节点一次,除非我想将它们作为单个节点并将节点标记为红色以区分。
一个节点仅应映射一次,例如,如果我要映射10,则它在第一张图上具有优先级20
和描述1
,然后找到相同的优先级,并且第二张图上的说明。为此,这里有60个。除60之外,没有其他节点。但是,如果我们在第一个图上使用Start
,则它具有优先级2和描述20
。在第二张图上,有两个节点的优先级为left
,描述为2
,描述为left
。这会造成混乱。我不能像70 and 80
这样两次映射20。但是我想将它们作为单个节点放置,如下面的示例图所示。
我期待以下结果。
要获得上述结果,我尝试了以下python代码。
20/70 and 20/80
任何人都可以帮助我达到/ graph /图所示的上述结果吗?任何帮助表示赞赏。
答案 0 :(得分:2)
我要解决的方法是,使用两个图的nx.union
构建一个新图,然后将 start 和 end“组合”在一起节点,它们使用contracted_nodes
共享属性。
让我们先从数据框中创建两个图:
df1 = df1.drop('To',1).join(df1.To.str.replace(' ','').str.split(',').explode())
df2 = df2.drop('To',1).join(df2.To.str.replace(' ','').str.split(',').explode())
g1 = nx.from_pandas_edgelist(df1.iloc[:-1,[0,3]].astype(int),
source='From', target='To', create_using=nx.DiGraph)
g2 = nx.from_pandas_edgelist(df2.iloc[:-1,[0,3]].astype(int),
source='From', target='To', create_using=nx.DiGraph)
df1_node_ix = df1.assign(graph='graph1').set_index('From').rename_axis('nodes')
nx.set_node_attributes(g1, values=df1_node_ix.description.to_dict(),
name='description')
nx.set_node_attributes(g1, values=df1_node_ix.priority.to_dict(),
name='priority')
nx.set_node_attributes(g1, values=df1_node_ix.graph.to_dict(),
name='graph')
df2_node_ix = df2.assign(graph='graph2').set_index('From').rename_axis('nodes')
nx.set_node_attributes(g2, values=df2_node_ix.description.to_dict(),
name='description')
nx.set_node_attributes(g2, values=df2_node_ix.priority.to_dict(),
name='priority')
nx.set_node_attributes(g2, values=df2_node_ix.graph.to_dict(),
name='graph')
现在通过获取两个图的nx.union
,我们可以:
g3 = nx.union(g1,g2)
from networkx.drawing.nx_agraph import graphviz_layout
plt.figure(figsize=(8,5))
pos=graphviz_layout(g3, prog='dot')
nx.draw(g3, pos=pos,
with_labels=True,
node_size=1500,
node_color='red',
arrowsize=20)
我们现在所能做的就是提出一些数据结构,稍后我们可以使用它们轻松地组合共享属性的节点对。为此,我们可以按其描述对节点进行排序。对它们进行排序将使我们能够使用itertools.groupby
来对连续相等的节点对进行分组,然后我们可以使用nx.contrated_nodes
轻松地将其合并,然后仅覆盖同一先前的图。可以按照问题中的nx.relabel_nodes
重新标记节点:
from itertools import groupby
g3_node_view = g3.nodes(data=True)
sorted_by_descr = sorted(g3_node_view, key=lambda x: x[1]['description'])
node_colors = dict()
colors = {'Bottom':'saddlebrown', 'Start':'lightblue',
'Left':'green', 'End':'lightblue'}
all_graphs = {'graph1', 'graph2'}
for _, grouped_by_descr in groupby(sorted_by_descr,
key=lambda x: x[1]['description']):
for _, group in groupby(grouped_by_descr, key=lambda x: x[1]['priority']):
grouped_nodes = list(group)
nodes = [i[0] for i in grouped_nodes]
graphs = {i[1]['graph'] for i in grouped_nodes}
# check if there are two nodes that share attributes
# and both belong to different graphs
if len(nodes)==2 and graphs==all_graphs:
# contract both nodes and update graph
g3 = nx.contracted_nodes(g3, *nodes)
# define new contracted node name and relabel
new_node = '/'.join(map(str, nodes))
g3 = nx.relabel_nodes(g3, {nodes[0]:new_node})
node_colors[new_node] = colors[grouped_nodes[0][1]['description']]
else:
for node in nodes:
node_colors[node] = 'red'
哪个会给:
plt.figure(figsize=(10,7))
pos=graphviz_layout(g3, prog='dot')
nx.draw(g3, pos=pos,
with_labels=True,
node_size=2500,
nodelist=node_colors.keys(),
node_color=node_colors.values(),
arrowsize=20)