web-dev-qa-db-ja.com

networkxでコミュニティを描く方法

この画像のようにpython networkxを使用して、コミュニティでグラフを描画するにはどうすればよいですか?

enter image description here

画像のURL

10
fullOfQuestion

networkx.draw_networkx_nodesおよびnetworkx.draw_networkx_edgesのドキュメントでは、ノードとエッジの色を設定する方法について説明しています。コミュニティの境界となるパッチは、各コミュニティのノードの位置を見つけてから、すべての位置(および一部)を含むパッチ(例:matplotlib.patches.Circle)を描画することで作成できます。

ハードビットはグラフレイアウト/ノード位置の設定です。 AFAIK、networkxには、「箱から出して」目的のグラフレイアウトを実現するためのルーチンはありません。あなたがしたいことは次のとおりです。

1)コミュニティを相互に配置します。新しい重み付きグラフを作成します。各ノードはコミュニティに対応し、重みはコミュニティ間のエッジの数に対応します。お気に入りのグラフレイアウトアルゴリズム(例:spring_layout)を使用して適切なレイアウトを取得します。

2)各コミュニティ内にノードを配置します。コミュニティごとに、新しいグラフを作成します。サブグラフのレイアウトを見つけます。

3)1)と3)のノード位置を組み合わせます。例えば。 1)で計算されたコミュニティの位置を10倍にスケーリングします。そのコミュニティ内のすべてのノード(2で計算)の位置にこれらの値を追加します。

私はしばらくの間これを実装したいと思っていました。私は今日遅くまたは週末にそれをするかもしれません。

編集:

出来上がり。ここで、ノードの周り(背後)にお気に入りのパッチを描画する必要があります。

Output of test()

import numpy as np
import matplotlib.pyplot as plt
import networkx as nx

def community_layout(g, partition):
    """
    Compute the layout for a modular graph.


    Arguments:
    ----------
    g -- networkx.Graph or networkx.DiGraph instance
        graph to plot

    partition -- dict mapping int node -> int community
        graph partitions


    Returns:
    --------
    pos -- dict mapping int node -> (float x, float y)
        node positions

    """

    pos_communities = _position_communities(g, partition, scale=3.)

    pos_nodes = _position_nodes(g, partition, scale=1.)

    # combine positions
    pos = dict()
    for node in g.nodes():
        pos[node] = pos_communities[node] + pos_nodes[node]

    return pos

def _position_communities(g, partition, **kwargs):

    # create a weighted graph, in which each node corresponds to a community,
    # and each Edge weight to the number of edges between communities
    between_community_edges = _find_between_community_edges(g, partition)

    communities = set(partition.values())
    hypergraph = nx.DiGraph()
    hypergraph.add_nodes_from(communities)
    for (ci, cj), edges in between_community_edges.items():
        hypergraph.add_Edge(ci, cj, weight=len(edges))

    # find layout for communities
    pos_communities = nx.spring_layout(hypergraph, **kwargs)

    # set node positions to position of community
    pos = dict()
    for node, community in partition.items():
        pos[node] = pos_communities[community]

    return pos

def _find_between_community_edges(g, partition):

    edges = dict()

    for (ni, nj) in g.edges():
        ci = partition[ni]
        cj = partition[nj]

        if ci != cj:
            try:
                edges[(ci, cj)] += [(ni, nj)]
            except KeyError:
                edges[(ci, cj)] = [(ni, nj)]

    return edges

def _position_nodes(g, partition, **kwargs):
    """
    Positions nodes within communities.
    """

    communities = dict()
    for node, community in partition.items():
        try:
            communities[community] += [node]
        except KeyError:
            communities[community] = [node]

    pos = dict()
    for ci, nodes in communities.items():
        subgraph = g.subgraph(nodes)
        pos_subgraph = nx.spring_layout(subgraph, **kwargs)
        pos.update(pos_subgraph)

    return pos

def test():
    # to install networkx 2.0 compatible version of python-louvain use:
    # pip install -U git+https://github.com/taynaud/python-louvain.git@networkx2
    from community import community_louvain

    g = nx.karate_club_graph()
    partition = community_louvain.best_partition(g)
    pos = community_layout(g, partition)

    nx.draw(g, pos, node_color=partition.values()); plt.show()
    return
9
Paul Brodersen