【问题标题】:Improving Python NetworkX graph layout改进 Python NetworkX 图形布局
【发布时间】: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,它有很多布局算法和其他有用的可视化功能。

标签: python networkx


【解决方案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 的问题请参考stackoverflow.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:

  1. 通常建议根据图中的节点数调整len
  2. len 属性只能被 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?


    改进的情节布局

    在这些静态 networkx / matplotlib 图中很难减少拥塞;一种解决方法是增加图形大小,根据此 StackOverflow 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? stackoverflow.com/questions/14679434/… | stackoverflow.com/questions/56672123/…
    • @Bendemann ...另外,请参阅上面接受的答案-也许明确指定prog而不是neato可能有效? "prog (string (default: 'neato')) - 用于布局的 GraphViz 程序的名称。选项取决于 GraphViz 版本,但可能包括:'dot'、'twopi'、'fdp'、'sfdp'、'圆'" | networkx.github.io/documentation/stable/reference/generated/…
    猜你喜欢
    • 2021-05-14
    • 2017-12-23
    • 1970-01-01
    • 1970-01-01
    • 2017-09-13
    • 1970-01-01
    • 2021-03-03
    • 1970-01-01
    • 2021-02-28
    相关资源
    最近更新 更多