簡體   English   中英

如何用networkx繪制社區

[英]how to draw communities with networkx

我如何使用 python networkx 繪制它的社區圖,如下圖:

在此處輸入圖片說明

圖片網址

networkx.draw_networkx_nodesnetworkx.draw_networkx_edges的文檔解釋了如何設置節點和邊緣顏色。 可以通過為每個社區找到節點的位置,然后繪制一個包含所有位置(然后是一些)的補丁(例如matplotlib.patches.Circle )來制作社區邊界的補丁。

難點是圖形布局/設置節點位置。 AFAIK,networkx 中沒有例程來實現“開箱即用”的所需圖形布局。 您想要做的是以下內容:

  1. 相對於彼此定位社區:創建一個新的加權圖,其中每個節點對應一個社區,權重對應於社區之間的邊數。 使用您最喜歡的圖形布局算法(例如spring_layout )獲得合適的布局。

  2. 在每個社區中放置節點:為每個社區創建一個新圖。 找到子圖的布局。

  3. 結合 1) 和 3) 中的節點位置。 例如,將 1) 中計算的社區位置按 10 倍計算; 將這些值添加到該社區內所有節點的位置(如在 2)中計算)。

我一直想實現這一點。 我可能會在今天晚些時候或周末做。

編輯:

瞧。 現在你只需要在節點周圍(后面)繪制你最喜歡的補丁。

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=list(partition.values())); plt.show()
    return

附錄

雖然總體思路是合理的,但我上面的舊實現有一些問題。 最重要的是,對於規模不均勻的社區,實施效果不佳。 具體來說, _position_communities在畫布上為每個社區提供相同數量的不動產。 如果某些社區比其他社區大得多,這些社區最終會被壓縮成與小社區相同的空間。 顯然,這並不能很好地反映圖的結構。

我編寫了一個用於可視化網絡的庫,稱為netgraph 它包括上述社區布局例程的改進版本,在安排社區時也會考慮社區的大小。 它與networkxigraph Graph 對象完全兼容,因此制作漂亮的圖形應該很容易和快速(至少這是想法)。

在此處輸入圖片說明

import matplotlib.pyplot as plt
import networkx as nx

# installation easiest via pip:
# pip install netgraph
from netgraph import Graph

# create a modular graph
partition_sizes = [10, 20, 30, 40]
g = nx.random_partition_graph(partition_sizes, 0.5, 0.1)

# since we created the graph, we know the best partition:
node_to_community = dict()
node = 0
for community_id, size in enumerate(partition_sizes):
    for _ in range(size):
        node_to_community[node] = community_id
        node += 1

# # alternatively, we can infer the best partition using Louvain:
# from community import community_louvain
# node_to_community = community_louvain.best_partition(g)

community_to_color = {
    0 : 'tab:blue',
    1 : 'tab:orange',
    2 : 'tab:green',
    3 : 'tab:red',
}
node_color = {node: community_to_color[community_id] for node, community_id in node_to_community.items()}

Graph(g,
      node_color=node_color, node_edge_width=0, edge_alpha=0.1,
      node_layout='community', node_layout_kwargs=dict(node_to_community=node_to_community),
      edge_layout='bundled', edge_layout_kwargs=dict(k=2000),
)

plt.show()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM