改进 Python NetworkX 图形布局

Posted

技术标签:

【中文标题】改进 Python NetworkX 图形布局【英文标题】:Improving Python NetworkX graph layout 【发布时间】:2014-03-25 13:38:12 【问题描述】:

我在可视化使用 python-networkx 创建的图形时遇到了一些问题,我希望能够减少混乱并调节节点之间的距离(我也尝试过 spring_layout,它只是以椭圆方式布置节点) .请指教。

部分代码:

nx.draw_networkx_edges(G, pos, edgelist=predges, edge_color='red', arrows=True)
nx.draw_networkx_edges(G, pos, edgelist=black_edges, arrows=False, style='dashed')
# label fonts
nx.draw_networkx_labels(G,pos,font_size=7,font_family='sans-serif')
nx.draw_networkx_edge_labels(G,pos,q_list,label_pos=0.3)

【问题讨论】:

我认为最好将您的图表导出到 Gephi,它有很多布局算法和其他有用的可视化功能。 【参考方案1】:

您的图表中有大量数据,因此很难消除混乱。

我建议您使用任何标准布局。你说你使用了spring_layout。我建议您再试一次,但这次在添加边时使用weight 属性。

例如:

import networkx as nx

G = nx.Graph();
G.add_node('A')
G.add_node('B')
G.add_node('C')
G.add_node('D')
G.add_edge('A','B',weight=1)
G.add_edge('C','B',weight=1)
G.add_edge('B','D',weight=30)

pos = nx.spring_layout(G,scale=2)

nx.draw(G,pos,font_size=8)
plt.show()

此外,您可以使用参数scale 来增加节点之间的全局距离。

【讨论】:

权重如何影响算法?权重越高 == 节点越靠近或相反?【参考方案2】:

在networkx中,值得一试graphviz通过nx.graphviz_layout提供的图形绘制算法。

我在neato 方面取得了很好的成功,但其他可能的输入是

dot - 有向图的“分层”或分层绘图。这是边缘具有方向性时使用的默认工具。

neato - “弹簧模型”布局。如果图形不太大(大约 100 个节点)并且您对此一无所知,这是默认使用的工具。Neato 尝试最小化一个全局能量函数,相当于统计多维缩放。

fdp - “弹簧模型”的布局类似于neato 的布局,但通过减少力而不是使用能量来实现。

sfdp - 用于大图布局的多尺度版本的 fdp。

twopi - 径向布局,在 Graham Wills 97 之后。节点放置在同心圆上,具体取决于它们与给定根节点的距离。

circo - 圆形布局,在 Six 和 Tollis 99、Kauffman 和 Wiese 02 之后。这适用于多个循环结构的某些图表,例如某些电信网络。

一般来说,graph drawing 是一个难题。如果这些算法还不够,您将不得不自己编写或让 networkx 单独绘制部件。

【讨论】:

graphviz_layout 的问题请参考***.com/questions/35279733/… 用法:nx.draw(G, pos=graphviz_layout(G)) 添加到@DiCaprio,首先安装pygraphviz:pip install pygraphviz 然后nx.draw(G, pos=nx.nx_agraph.graphviz_layout(G)) pip install pygraphviz 在 Windows 上出现错误(与***有关),但由于我使用 Anacondaconda install -c anaconda graphviz 工作正常【参考方案3】:

为了回答你的问题如何调节节点之间的距离,我扩展了Hooked's answer:

如果您通过 Graphviz 后端绘制图形,然后使用fdp 算法,您可以通过edge attribute len 调整节点之间的距离。

这里是一个代码示例,如何绘制图形G 并保存在Graphviz 文件gvfile 中,节点间距离较宽(fdp 的默认距离为0.3):

A = nx.to_agraph(G)
A.edge_attr.update(len=3)
A.write(gv_file_name)

两个cmets:

    通常建议根据图中的节点数调整lenlen 属性只能被 fdpneato 算法识别,但不能被例如通过sfdp 算法。

【讨论】:

【参考方案4】:

我发现这对于快速可视化来自 CSV 文件的交互数据(此处为基因)很有用。

数据文件 [a.csv]

APC,TP73
BARD1,BRCA1
BARD1,ESR1
BARD1,KRAS2
BARD1,SLC22A18
BARD1,TP53
BRCA1,BRCA2
BRCA1,CHEK2
BRCA1,MLH1
BRCA1,PHB
BRCA2,CHEK2
BRCA2,TP53
CASP8,ESR1
CASP8,KRAS2
CASP8,PIK3CA
CASP8,SLC22A18
CDK2,CDKN1A
CHEK2,CDK2
ESR1,BRCA1
ESR1,KRAS2
ESR1,PPM1D
ESR1,SLC22A18
KRAS2,BRCA1
MLH1,CHEK2
MLH1,PMS2
PIK3CA,BRCA1
PIK3CA,ESR1
PIK3CA,RB1CC1
PIK3CA,SLC22A18
PMS2,TP53
PTEN,BRCA1
PTEN,MLH3
RAD51,BRCA1
RB1CC1,SLC22A18
SLC22A18,BRCA1
TP53,PTEN

Python 3.7 venv

import networkx as nx
import matplotlib.pyplot as plt
G = nx.read_edgelist("a.csv", delimiter=",")

G.edges()
'''
  [('CDKN1A', 'CDK2'), ('MLH3', 'PTEN'), ('TP73', 'APC'), ('CHEK2', 'MLH1'),
    ('CHEK2', 'BRCA2'), ('CHEK2', 'CDK2'), ('CHEK2', 'BRCA1'), ('BRCA2', 'TP53'),
    ('BRCA2', 'BRCA1'), ('KRAS2', 'CASP8'), ('KRAS2', 'ESR1'), ('KRAS2', 'BRCA1'),
    ('KRAS2', 'BARD1'), ('PPM1D', 'ESR1'), ('BRCA1', 'PHB'), ('BRCA1', 'ESR1'),
    ('BRCA1', 'PIK3CA'), ('BRCA1', 'PTEN'), ('BRCA1', 'MLH1'), ('BRCA1', 'SLC22A18'),
    ('BRCA1', 'BARD1'), ('BRCA1', 'RAD51'), ('CASP8', 'ESR1'), ('CASP8', 'SLC22A18'),
    ('CASP8', 'PIK3CA'), ('TP53', 'PMS2'), ('TP53', 'PTEN'), ('TP53', 'BARD1'),
    ('PMS2', 'MLH1'), ('PIK3CA', 'SLC22A18'), ('PIK3CA', 'ESR1'), ('PIK3CA', 'RB1CC1'),
    ('SLC22A18', 'ESR1'), ('SLC22A18', 'RB1CC1'), ('SLC22A18', 'BARD1'), 
    ('BARD1', 'ESR1')]
'''
G.number_of_edges()
# 36

G.nodes()
'''
  ['CDKN1A', 'MLH3', 'TP73', 'CHEK2', 'BRCA2', 'KRAS2', 'CDK2', 'PPM1D', 'BRCA1',
    'CASP8', 'TP53', 'PMS2', 'RAD51', 'PIK3CA', 'MLH1', 'SLC22A18', 'BARD1',
    'PHB', 'APC', 'ESR1', 'RB1CC1', 'PTEN']
'''
G.number_of_nodes()
# 22

更新

这曾经有效(2018-03),但现在(2019-12)给出了pygraphviz导入错误:

from networkx.drawing.nx_agraph import graphviz_layout

nx.draw(G, pos = graphviz_layout(G), node_size=1200, node_color='lightblue', \
    linewidths=0.25, font_size=10, font_weight='bold', with_labels=True)

    Traceback (most recent call last):
    ...
    ImportError: libpython3.7m.so.1.0: cannot open shared object file:
      No such file or directory
    During handling of the above exception, another exception occurred:
      Traceback (most recent call last):
    ...
    ImportError: ('requires pygraphviz ', 'http://pygraphviz.github.io/')

解决方案

在 Python 外部(在 venv 终端提示符处:$)安装 pydot

pip install pydot

回到 Python 中运行以下代码。

import warnings
warnings.filterwarnings("ignore", category=UserWarning)

import networkx as nx
import matplotlib.pyplot as plt

G = nx.read_edgelist("a.csv", delimiter=",")
# For a DiGraph() [directed edges; not shown]:
#   G = nx.read_edgelist("a.csv", delimiter=",", create_using=nx.DiGraph)

nx.draw(G, pos = nx.nx_pydot.graphviz_layout(G), node_size=1200, \
    node_color='lightblue', linewidths=0.25, font_size=10, \
    font_weight='bold', with_labels=True)

plt.show()    ## plot1.png attached

主要的变化是替换

nx.draw(G, pos = graphviz_layout(G), ...)

nx.draw(G, pos = nx.nx_pydot.graphviz_layout(G), ...)

参考文献

Remove matplotlib depreciation warning from showing

What could cause NetworkX & PyGraphViz to work fine alone but not together?

具体:https://***.com/a/40750101/1904943

改进的情节布局

在这些静态 networkx / matplotlib 图中很难减少拥塞;一种解决方法是增加图形大小,根据此 *** Q/A:High Resolution Image of a Graph using NetworkX and Matplotlib:

plt.figure(figsize=(20,14))
# <matplotlib.figure.Figure object at 0x7f1b65ea5e80>

nx.draw(G, pos = nx.nx_pydot.graphviz_layout(G), \
    node_size=1200, node_color='lightblue', linewidths=0.25, \
    font_size=10, font_weight='bold', with_labels=True, dpi=1000)

plt.show()    ## plot2.png attached

将输出图形大小重置为系统默认值:

plt.figure()
# <matplotlib.figure.Figure object at 0x7f1b454f1588>

奖励:最短路径

nx.dijkstra_path(G, 'CDKN1A', 'MLH3')
# ['CDKN1A', 'CDK2', 'CHEK2', 'BRCA1', 'PTEN', 'MLH3']


plot1.png

plot2.png


虽然我这里没有做,但是如果要添加节点边框,加粗节点边框线(节点边缘粗细:linewidths),请执行以下操作。

nx.draw(G, pos = nx.nx_pydot.graphviz_layout(G), \
    node_size=1200, node_color='lightblue', linewidths=2.0, \
    font_size=10, font_weight='bold', with_labels=True)
# Get current axis:
ax = plt.gca()
ax.collections[0].set_edgecolor('r')
# r : red (can also use #FF0000) | b : black (can also use #000000) | ...
plt.show()

【讨论】:

你,妈妈,是个英雄。特别是,此答案中.draw 中的选项文档超过了实际networkx 文档中的类似文档,IMO。 @MaxvonHippel :你评论中的喜悦胜过我在这个答案上得到的任何支持! ;-) 当我后来返回此代码时(大约 21 个月后),我收到了 pygraphviz 导入错误。 pip install pygraphviz 似乎进展顺利,但我不能 import pygraphviz (同样的错误;在我的 Arch Linux 系统上我通过 yay -S python-pygraphviz 安装 python-pygraphviz 时也是如此。我用解决方案更新了上面的答案。 @Bendemann :您使用的是 Windows?我不知道; h/e 在我的(Arch Linux)系统上,而 NetworkX 作为一个包提供,我没有通过我的操作系统安装它,而是通过 Python 中的 pip (pip list | grep networkx; pip show networkx) 安装它。检查这些帖子中的 cmets? ***.com/questions/14679434/… | ***.com/questions/56672123/… @Bendemann ...另外,请参阅上面接受的答案-也许明确指定prog而不是neato可能有效? "prog (string (default: 'neato')) - 用于布局的 GraphViz 程序的名称。选项取决于 GraphViz 版本,但可能包括:'dot'、'twopi'、'fdp'、'sfdp'、'圆'" | networkx.github.io/documentation/stable/reference/generated/…

以上是关于改进 Python NetworkX 图形布局的主要内容,如果未能解决你的问题,请参考以下文章

Networkx 图形 python

使用 nx.draw_graphviz 在 python 中的 graphviz 布局中绘制图形给出错误

python学习(32)---networkx

Plotly Dash:在 Python 中绘制 networkx

Python数模笔记-NetworkX图的操作

节点颜色 Networkx Python 3.8