【问题标题】:Networkx: Drawing parallel edgesNetworkx:绘制平行边
【发布时间】:2019-06-11 12:17:48
【问题描述】:

使用以下代码从数据框中绘制图表:

import pandas as pd
import networkx as nx

df = pd.DataFrame({'id_emp' : [13524791000109, 12053850000137, 4707821000113, 4707821000114, 1],
           'name_emp': ['Cristiano', 'Gaúcho', 'Fenômeno','Angelin', 'Souza'],
           'name_dep': ['Ronaldo','Ronaldo', 'Ronaldo', 'Ronaldo', 'Bruno'],
           'weight_1': [8,9,10,11,12],
           'weight_2':[5,6,7,8,9] })

 G = nx.MultiDiGraph()

 G.add_nodes_from(df['id_emp'], bipartite = 0)
 emp = [v for v in G.nodes if G.nodes[v]['bipartite'] == 0]

 G.add_nodes_from(df['name_dep'], bipartite = 1)
 dep = [v for v in G.nodes if G.nodes[v]['bipartite'] == 1]

 G.add_weighted_edges_from(df[['name_dep', 'id_emp', 'weight_1']].values)
 G.add_weighted_edges_from(df[['id_emp', 'name_dep', 'weight_2']].values)
 edge_width = [a[2]['weight']//2 for a in G.edges(data=True)]

 plt.figure(figsize=(5,5))

 pos = nx.spring_layout(G, k=0.9)
 nx.draw_networkx_nodes(G, pos, nodelist=dep, node_color='#bfbf7f', node_shape="h", node_size=300, with_labels = True)
 nx.draw_networkx_nodes(G, pos, nodelist=emp, node_color='red', node_size=300, with_labels = True)
 nx.draw_networkx_edges(G, pos, width=edge_width, alpha=0.2)

 plt.axis('off')
 plt.show()

输出:

在所示示例中,每个顶点都有一条输入边和一条输出边,这将配置两个顶点之间的平行边。然而,networkx 绘制了边缘相互重叠的图形,给人的印象是两个顶点之间只有一条边。那么,如何配置 networkx 以使输出类似于下图?

【问题讨论】:

    标签: python pandas networkx


    【解决方案1】:

    Networkx 无法正确绘制平行边。如果要绘制它们,则需要使用带有write_dot 函数的Graphviz (Agraph) 创建一个DOT 文件,然后将其转换为图像:

    nx.nx_agraph.write_dot(G, path_to_store_dot_file)

    【讨论】:

    • 我总是这样做以可视化它们。
    【解决方案2】:

    您也可以使用graphviz python 库。

    sudo apt-get install graphviz
    pip install graphviz
    

    我在 Jupyter notebook 上试过(原生支持)

    import pandas as pd
    import networkx as nx
    
    df = pd.DataFrame({'id_emp' : [13524791000109, 12053850000137, 4707821000113, 4707821000114, 1],
               'name_emp': ['Cristiano', 'Gaúcho', 'Fenômeno','Angelin', 'Souza'],
               'name_dep': ['Ronaldo','Ronaldo', 'Ronaldo', 'Ronaldo', 'Bruno'],
               'weight_1': [8,9,10,11,12],
               'weight_2':[5,6,7,8,9] })
    
    G = nx.MultiDiGraph()
    
    G.add_nodes_from(df['id_emp'], bipartite = 0)
    emp = [v for v in G.nodes if G.nodes[v]['bipartite'] == 0]
    
    G.add_nodes_from(df['name_dep'], bipartite = 1)
    dep = [v for v in G.nodes if G.nodes[v]['bipartite'] == 1]
    
    G.add_weighted_edges_from(df[['name_dep', 'id_emp', 'weight_1']].values)
    G.add_weighted_edges_from(df[['id_emp', 'name_dep', 'weight_2']].values)
    edge_width = [a[2]['weight']//2 for a in G.edges(data=True)]
    
    ########################################################################
    ###########################CODE TO ADD##################################
    ########################################################################
    import graphviz
    
    d = graphviz.Digraph()
    
    for n in dep:
        d.node(str(n), color="#bfbf7f")
    
    for n in emp:
        d.node(str(n), color="red")
    
    for e in G.edges:
        d.edge(str(e[0]), str(e[1]))
    
    d.attr(size='8')
    
    # To display the graph on Jupyter
    d
    

    显示:

    【讨论】:

      【解决方案3】:

      我发现@AMangipinto 的回答不起作用(使用 nx 2.2 版):另一种方法是之后直接用 matplotlib 绘制边缘:

          import pandas as pd
      import networkx as nx
      
      df = pd.DataFrame({'id_emp' : [13524791000109, 12053850000137, 4707821000113, 4707821000114, 1],
                 'name_emp': ['Cristiano', 'Gaúcho', 'Fenômeno','Angelin', 'Souza'],
                 'name_dep': ['Ronaldo','Ronaldo', 'Ronaldo', 'Ronaldo', 'Bruno'],
                 'weight_1': [8,9,10,11,12],
                 'weight_2':[5,6,7,8,9] })
      
      G = nx.MultiDiGraph()
      
      G.add_nodes_from(df['id_emp'], bipartite = 0)
      emp = [v for v in G.nodes if G.nodes[v]['bipartite'] == 0]
      G.add_nodes_from(df['name_dep'], bipartite = 1)
      dep = [v for v in G.nodes if G.nodes[v]['bipartite'] == 1]
      
      G.add_weighted_edges_from(df[['name_dep', 'id_emp', 'weight_1']].values)
      G.add_weighted_edges_from(df[['id_emp', 'name_dep', 'weight_2']].values)
      edge_width = [a[2]['weight']//2 for a in G.edges(data=True)]
      
      plt.figure(figsize=(5,5))
      
      pos = nx.spring_layout(G, k=0.9)
      
      
      nx.draw_networkx_nodes(G, pos, nodelist=dep, node_color='#bfbf7f', node_shape="h", node_size=300, with_labels = True)
      nx.draw_networkx_nodes(G, pos, nodelist=emp, node_color='red', node_size=300, with_labels = True)
      ax = plt.gca()
      for edge in G.edges:
          ax.annotate("",
                      xy=pos[edge[0]], xycoords='data',
                      xytext=pos[edge[1]], textcoords='data',
                      arrowprops=dict(arrowstyle="->", color="0.5",
                                      shrinkA=5, shrinkB=5,
                                      patchA=None, patchB=None,
                                      connectionstyle="arc3,rad=-0.3",
                                      ),
                      )
      
      plt.axis('off')
      plt.show()
      

      【讨论】:

        【解决方案4】:

        我还找到了解决此问题的更快方法。这是将 connectionstyle 关键字添加到 nx.draw_networkx_nodes。

        所以特别是你的情况:

        import pandas as pd
        import networkx as nx
        
        df = pd.DataFrame({'id_emp' : [13524791000109, 12053850000137, 4707821000113, 4707821000114, 1],
                   'name_emp': ['Cristiano', 'Gaúcho', 'Fenômeno','Angelin', 'Souza'],
                   'name_dep': ['Ronaldo','Ronaldo', 'Ronaldo', 'Ronaldo', 'Bruno'],
                   'weight_1': [8,9,10,11,12],
                   'weight_2':[5,6,7,8,9] })
        
        G = nx.MultiDiGraph()
        
        G.add_nodes_from(df['id_emp'], bipartite = 0)
        emp = [v for v in G.nodes if G.nodes[v]['bipartite'] == 0]
        G.add_nodes_from(df['name_dep'], bipartite = 1)
        dep = [v for v in G.nodes if G.nodes[v]['bipartite'] == 1]
        
        G.add_weighted_edges_from(df[['name_dep', 'id_emp', 'weight_1']].values)
        G.add_weighted_edges_from(df[['id_emp', 'name_dep', 'weight_2']].values)
        edge_width = [a[2]['weight']//2 for a in G.edges(data=True)]
        
        plt.figure(figsize=(5,5))
        
        pos = nx.spring_layout(G, k=0.9)
        
        # Here there is the addition:
        
        nx.draw_networkx_nodes(G, pos, connectionstyle='arc3, rad = 0.3', nodelist=dep, node_color='#bfbf7f', node_shape="h", node_size=300, with_labels = True)
        nx.draw_networkx_nodes(G, pos, connectionstyle='arc3, rad = 0.3', nodelist=emp, node_color='red', node_size=300, with_labels = True)
        nx.draw_networkx_edges(G, pos, connectionstyle='arc3, rad = 0.3', width=edge_width, alpha=0.2)
        
        plt.axis('off')
        plt.show()
        

        在这里你可以看到它的样子:

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-10-24
          • 2018-11-25
          • 2021-12-04
          • 2021-06-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多