aearslan
aearslan

Reputation: 168

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

Upvotes: 0

Views: 286

Answers (1)

Paul Brodersen
Paul Brodersen

Reputation: 13041

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()

Upvotes: 1

Related Questions