从 Pandas Dataframe 创建 Networkx 有向图时如何创建多线节点标签
How to create multi-line node labels when creating Networkx Directed Graphs from Pandas Dataframe
我的问题是 previous question 的延续。
我正在尝试从 pandas 数据帧创建一个 networkx 流程图。数据框记录订单如何流经多个公司。数据框中的大多数行都是连接的,并且连接显示在多列中。样本数据如下:
df = pd.DataFrame({'Company': ['A', 'A', 'B', 'B', 'B', 'C', 'C'],
'event_type':['new', 'route', 'receive', 'execute', 'route', 'receive', 'execute'],
'event_id': ['110', '120', '200', '210', '220', '300', '310'],
'prior_event_id': [np.nan, '110', np.nan, '120', '210', np.nan, '300'],
'route_id': [np.nan, 'foo', 'foo', np.nan, 'bar', 'bar', np.nan]}
)
数据框如下所示:
Company event_type event_id prior_event_id route_id
0 A new 110 NaN NaN
1 A route 120 110 foo
2 B receive 200 NaN foo
3 B execute 210 120 NaN
4 B route 220 210 bar
5 C receive 300 NaN bar
6 C execute 310 300 NaN
我能够使用以下代码从示例数据创建源列和目标列:
df['event_sub'] = df.groupby([df.Company, df.event_type]).cumcount()+1
df['event'] = df.Company + ' ' + df.event_type + ' ' + df.event_sub.astype(str)
replace_dict_event = dict(df[['event_id', 'event']].values)
df['source'] = df['prior_event_id'].apply(lambda x: replace_dict_event.get(x) if replace_dict_event.get(x) else np.nan )
df['target'] = df['event_id'].apply(lambda x: replace_dict_event.get(x) if replace_dict_event.get(x) else np.nan )
replace_dict_rtd = dict(df[df.event_type == 'route'][['route_id', 'event']].values)
df.loc[df.event_type == 'receive', 'source'] = df[df.event_type == 'receive']['route_id'].apply(lambda x: replace_dict_rtd.get(x))
现在数据框看起来像这样:
上面的结果与我上一个问题的结果略有不同的是,我在当前结果中加入了公司名称。我从 source
和 target
列创建的 networkx 图如下所示:
但是,我面临的问题是,在我的实际数据中,公司名称较长,节点较多。因此,很多时候标签都挤在一起,基本上变得难以理解。我想到的第一个解决方案是将标签分成多行。我想要的节点如下所示:
我尝试在相关列中添加“\n”,因此我将最后一个代码块的第 2 行更改为
df['event'] = df.Company + '\n' + df.event_type + ' ' + df.event_sub.astype(str)
但这并没有给我我想要的。相反,我得到了“KeyError:'Node A\nnew 1 not in graph.'”我尝试了一些我在 SO 上找到的其他方法,但也没有运气。
有什么办法可以实现吗?
# dummy data
a = np.random.randint(0,2,size=(10,10))
G = nx.from_numpy_matrix(a)
pos = nx.spring_layout(G)
# draw without labels, then draw labels separately
nx.draw_networkx(G, pos=pos, with_labels=False)
# draw_networkx_labels takes as keyword argument a dictionary called labels
# which links the id of a node to a name.
# you can create one using dictionary comprehension like so:
nodenames = {n:'firstline \n secondline \n thirdline' for n in G.nodes()}
# and then draw:
nx.draw_networkx_labels(G, pos=pos, labels=nodenames);
我的问题是 previous question 的延续。
我正在尝试从 pandas 数据帧创建一个 networkx 流程图。数据框记录订单如何流经多个公司。数据框中的大多数行都是连接的,并且连接显示在多列中。样本数据如下:
df = pd.DataFrame({'Company': ['A', 'A', 'B', 'B', 'B', 'C', 'C'],
'event_type':['new', 'route', 'receive', 'execute', 'route', 'receive', 'execute'],
'event_id': ['110', '120', '200', '210', '220', '300', '310'],
'prior_event_id': [np.nan, '110', np.nan, '120', '210', np.nan, '300'],
'route_id': [np.nan, 'foo', 'foo', np.nan, 'bar', 'bar', np.nan]}
)
数据框如下所示:
Company event_type event_id prior_event_id route_id
0 A new 110 NaN NaN
1 A route 120 110 foo
2 B receive 200 NaN foo
3 B execute 210 120 NaN
4 B route 220 210 bar
5 C receive 300 NaN bar
6 C execute 310 300 NaN
我能够使用以下代码从示例数据创建源列和目标列:
df['event_sub'] = df.groupby([df.Company, df.event_type]).cumcount()+1
df['event'] = df.Company + ' ' + df.event_type + ' ' + df.event_sub.astype(str)
replace_dict_event = dict(df[['event_id', 'event']].values)
df['source'] = df['prior_event_id'].apply(lambda x: replace_dict_event.get(x) if replace_dict_event.get(x) else np.nan )
df['target'] = df['event_id'].apply(lambda x: replace_dict_event.get(x) if replace_dict_event.get(x) else np.nan )
replace_dict_rtd = dict(df[df.event_type == 'route'][['route_id', 'event']].values)
df.loc[df.event_type == 'receive', 'source'] = df[df.event_type == 'receive']['route_id'].apply(lambda x: replace_dict_rtd.get(x))
现在数据框看起来像这样:
上面的结果与我上一个问题的结果略有不同的是,我在当前结果中加入了公司名称。我从 source
和 target
列创建的 networkx 图如下所示:
但是,我面临的问题是,在我的实际数据中,公司名称较长,节点较多。因此,很多时候标签都挤在一起,基本上变得难以理解。我想到的第一个解决方案是将标签分成多行。我想要的节点如下所示:
我尝试在相关列中添加“\n”,因此我将最后一个代码块的第 2 行更改为
df['event'] = df.Company + '\n' + df.event_type + ' ' + df.event_sub.astype(str)
但这并没有给我我想要的。相反,我得到了“KeyError:'Node A\nnew 1 not in graph.'”我尝试了一些我在 SO 上找到的其他方法,但也没有运气。
有什么办法可以实现吗?
# dummy data
a = np.random.randint(0,2,size=(10,10))
G = nx.from_numpy_matrix(a)
pos = nx.spring_layout(G)
# draw without labels, then draw labels separately
nx.draw_networkx(G, pos=pos, with_labels=False)
# draw_networkx_labels takes as keyword argument a dictionary called labels
# which links the id of a node to a name.
# you can create one using dictionary comprehension like so:
nodenames = {n:'firstline \n secondline \n thirdline' for n in G.nodes()}
# and then draw:
nx.draw_networkx_labels(G, pos=pos, labels=nodenames);