title: Group nodes together in networkx
body: <p>I have a visualization problem involving a graph. I have <code>N</code> nodes, which belong to say some <code>M</code> networks. The nodes can have inter-network edges (within the same network) and intra-network edges (edges from a node in one network to another one). </p>
  
  <p><a href="https://i.stack.imgur.com/DMRpk.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/DMRpk.png" alt="image"></a></p>
  
  <p>When I visualize the graph in <code>networkx</code> I am looking for a way to place/cluster the networks together so that I can easily make out the inter/intra network connections. So ideally all the blue nodes would be clustered together as network (in no particular order). Similarly for the orange or green ones. </p>
  
  <p>By the way I am not trying to find hubs/clusters, I <strong>know</strong> which nodes are in which networks, I just am trying to find a way to visualize it neater. Is there some easy way to do this? Something like an advanced spring layout where I can specify some nodes should show up together regardless of the edge weights / spring force?</p>
  
  <hr>
  
  <h2>Minimal working generator</h2>
  
  <pre><code>import string, random
  import networkx as nx
  import matplotlib.pyplot as plt
  from scipy.sparse import random as sparse_random
  
  
  # Random string generator
  def rand_string(size=6, chars=string.ascii_uppercase):
      return ''.join(random.choice(chars) for _ in range(size))
  
  
  # Set up a nodes and networks randomly
  nodes = [rand_string() for _ in range(30)]
  networks = [rand_string() for _ in range(5)]
  networks_list = networks*6
  random.shuffle(networks_list)
  
  # Define what nodes belong to what network and what their color should be
  node_network_map = dict(zip(nodes, networks_list))
  colors = ['green', 'royalblue', 'red', 'orange', 'cyan']
  color_map = dict(zip(networks, colors))
  
  graph = nx.Graph()
  graph.add_nodes_from(nodes)
  nodes_by_color = {val: [node for node in graph if color_map[node_network_map[node]] == val]
                    for val in colors}
  
  # Take random sparse matrix as adjacency matrix
  mat = sparse_random(30, 30, density=0.3).todense()
  for row, row_val in enumerate(nodes):
      for col, col_val in enumerate(nodes):
          if col &gt; row and mat[row, col] != 0.0: # Stick to upper half triangle, mat is not symmetric
              graph.add_edge(row_val, col_val, weight=mat[row, col])
  
  # Choose a layout to visualize graph
  pos = nx.spring_layout(graph)
  edges = graph.edges()
  
  # Get the edge weights and normalize them 
  weights = [abs(graph[u][v]['weight']) for u, v in edges]
  weights_n = [5*float(i)/max(weights) for i in weights] # Change 5 to control thickness
  
  # First draw the nodes 
  plt.figure()
  for color, node_names in nodes_by_color.items():
      nx.draw_networkx_nodes(graph, pos=pos, nodelist=node_names, node_color=color)
  
  # Then draw edges with thickness defined by weights_n
  nx.draw_networkx_edges(graph, pos=pos, width=weights_n)
  nx.draw_networkx_labels(graph, pos=pos)
  plt.show()
  </code></pre>