Search code examples
graphnodesnetworkxedgescomplex-networks

NetworkX: connect nodes of two separate graphs in Python


This question is about attempting to model interdependent networks with NetworkX. There are dedicated packages (such as Pymnet), but they don't seem as flexible as NetworkX. And by the way, I wanted to give NetworkX one last chance.

So, let's say we have 2 separate graphs, G1 and G2, which we plot in the same figure:

import networkx as nx
import matplotlib.pyplot as plt

G1=nx.barabasi_albert_graph(3, 2) #n=3, m=2 (number of initial links)
G2=nx.barabasi_albert_graph(3, 2)
pos1=nx.spring_layout(G1)
pos2=nx.spring_layout(G2)
nx.draw_networkx(G1,pos=pos1,node_color='red') #G1 is red
nx.draw_networkx(G2,pos=pos2,node_color='green') #G2 is green

enter image description here

Now, if we attempt to connect node 0 of G1 with node 1 of G2:

G1.add_edge(G1.nodes()[0], G2.nodes()[1]) 

we don't get any error, but if you plot the graphs again, the image is exactly as before. And if you check the number of edges you get the same results as before:

In[17]: G1.edges()
Out[17]: [(0, 1), (0, 2), (1, 2)]

In[18]: G2.edges()
Out[18]: [(0, 2), (1, 2)]

meaning that the edge was basically not added, or it was added and is not displayed, or it was added, but because it runs from one graph to another, it doesn't belong to any of them.

How do you suggest to create this interconnection from G1 to G2 in NetworkX, without resorting to other packages?


Solution

  • I think the fundamental issue is that you've got a different concept for how networkx thinks of a graph from what it is. I believe you're thinking that the nodes of the graph are objects of some node class that the nodes themselves intrinsically have some attribute saying what their position is. This is not the case. There is no special node class. A graph can have any hashable object as its nodes because really, a graph is just a fancy dict whose keys are what we call nodes.

    The nodes of your graph G1 are the integers 0, 1, and 2. G2 has exactly the same nodes. The new edge you've added is between whatever integer is in G1.nodes()[0] and whatever integer is in G2.nodes()[1]. In your example I believe G1 already has that edge.

    Separately, you've created two different dicts pos1 and pos2 (which have the same keys - the integer values that form the nodes of the two graphs). These dicts say where the nodes should be plotted. You've told it to plot G1 using pos1. So it puts the circle for the node that is 0 at pos1[0] and similarly for 1 and 2. Then when you later tell it to plot G using pos1 it's going to do exactly the same thing.

    What you probably want to do is create a new graph whose nodes consist of the nodes of G1 and of G2, after renaming so that they aren't the same nodes. This is done by union (see documentation.)

    G = union(G1, G2, rename=('G1-', 'G2-'))
    

    Then add the edge, noting that the nodes in G have different names, so the command you used won't quite work.