como dibujar comunidades con networkx

¿Cómo puedo dibujar un gráfico con sus comunidades usando python networkx como esta imagen:

introduzca la descripción de la imagen aquí

URL de la imagen

La documentación para networkx.draw_networkx_nodes y networkx.draw_networkx_edges explica cómo configurar los colores de nodo y borde. Los parches que delimitan a las comunidades se pueden hacer buscando las posiciones de los nodos para cada comunidad y luego dibujando un parche (por ejemplo, matplotlib.patches.Circle ) que contiene todas las posiciones (y algunas).

El bit duro es el diseño del gráfico / configuración de las posiciones del nodo. AFAIK, no hay ninguna rutina en networkx para lograr el diseño gráfico deseado “fuera de la caja”. Lo que quieres hacer es lo siguiente:

1) Coloque las comunidades entre sí: cree un nuevo gráfico ponderado, donde cada nodo corresponda a una comunidad, y los pesos correspondan al número de bordes entre comunidades. Obtenga un diseño decente con su algoritmo de diseño gráfico favorito (por ejemplo, spring_layout ).

2) Posicione los nodos dentro de cada comunidad: para cada comunidad, cree un nuevo gráfico. Encuentra un diseño para el subgrafo.

3) Combinar posiciones de nodo en 1) y 3). Por ejemplo, escalar posiciones de la comunidad calculadas en 1) por un factor de 10; agregue esos valores a las posiciones de todos los nodos (como se calcula en 2) dentro de esa comunidad.

He estado queriendo implementar esto por un tiempo. Podría hacerlo más tarde hoy o durante el fin de semana.

EDITAR:

Voila Ahora solo necesita dibujar su parche favorito alrededor (detrás) de los nodos.

Salida de prueba ()

 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