从 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))

现在数据框看起来像这样:

上面的结果与我上一个问题的结果略有不同的是,我在当前结果中加入了公司名称。我从 sourcetarget 列创建的 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);