python-3.xnetwork-programmingnetworkxnetwork-analysispyvis

Networkx Multiple Circular Layouts Combined Together


I am trying to build a company connections network. in the center, the main company is located. in the inner circle there are its subsidiary companies. and the outer circle represents the companies that work with the subsidiary companies. i did the below network representation so far.

But here is the problem. i want the inner circle and the outer circle close to each other, in other words in the same direction. i keep the inner circle's coordinates but not able to calculate the outer circle's coordinates based on the fixed inner circle.


G1 = nx.from_pandas_edgelist(layer1_edges,
                           source='source',
                           target='target',
                           create_using=nx.MultiDiGraph())


pos1 = nx.circular_layout(G1,  scale=200, center=(0, 0))
pos1["centered_node"] = np.array([0.0, 0.0])

G2 = nx.from_pandas_edgelist(layer2_edges,
                           source='source',
                           target='target',
                           create_using=nx.MultiDiGraph())


pos2 = nx.circular_layout(G2,  scale=300, center=(0, 0))

F = nx.compose(G1, G2)
pos_f = pos1.copy()

for name, pos in pos2.items():
   if name not in pos_f:
       pos_f[name] = pos

enter image description here


Solution

  • The following answer assumes that the issue you are trying to solve is that nodes that are connected are typically not in close proximity to each other.

    It looks like you have a multi-partite network, and are trying to plot that the network with a shell layout. NetworkX does implement a shell layout. However, this function does not implement edge crossing reduction or any other technique such that connected nodes are close to each other in the visualization.

    As neither igraph of graph-tool seem to implement a shell layout, likely your only option is Netgraph, a library I wrote and maintain. Netgraph supports edge crossing reduction for a variety of node layouts, which in layered graphs typically has the effect that connected nodes are grouped together. For shell layouts, it uses the algorithm proposed in Eades & Wormald (1994). A tutorial can be found here. A simple visualisation similar to yours can be created using the following code:

    enter image description here

    import numpy as np
    import matplotlib.pyplot as plt
    import networkx as nx
    
    from itertools import product
    from netgraph import InteractiveGraph
    
    ################################################################################
    # SIMULATE DATA
    
    # initialize shells
    shell_sizes = [1, 20, 100]
    
    ctr = 0
    shells = []
    for size in shell_sizes:
        shells.append(list(range(ctr, ctr+size)))
        ctr += size
    
    # initialize edges
    multipartite_edges = []
    
    # the node in the first layer connects to all nodes in the second layer
    multipartite_edges.extend(list(product(shells[0], shells[1])))
    
    # nodes in subsequent layers only connect to a subset of nodes in the next layer
    minimum_edges = 1
    maximum_edges = 3
    for p1, p2 in zip(shells[1:-1], shells[2:]):
        for target in p2:
            total_edges = np.random.randint(minimum_edges, maximum_edges, 1)
            sources = np.random.choice(p1, total_edges, replace=False)
            multipartite_edges.extend([(source, target) for source in sources])
    
    graph = nx.Graph(multipartite_edges)
    
    ################################################################################
    # DRAW
    
    node_size = dict()
    for node in range(ctr):
        if node in shells[0]:
            node_size[node] = 9
        elif node in shells[1]:
            node_size[node] = 3
        else:
            node_size[node] = 1
    
    g = InteractiveGraph(
        graph, node_layout='shell',
        node_layout_kwargs=dict(shells=shells, reduce_edge_crossings=True),
        node_size=node_size,
        edge_width=0.5,
    )
    plt.show()