Networkx: Interconnect nodes between two graphs - python

I have graph A. For every node in Graph A, I use some rules to convert the name of the node and decide to add it to Graph B.
So now I have B derived from A. I was wondering if it is possible to create some sort of link between the original node in A and the transformed node in B.
I couldn't figure out a method to do it using networkx library. Any pointers would be helpful...

Nodes can have attributes. In each node in graph A, you can create an attribute to hold the corresponding node in graph B.
In the code below, graph A has 3 nodes: 1, 2, and 3. Graph B is created with nodes 1, 4, and 9 (the squares of the values of the nodes in A). As each node in B is created, its value is stored in the b_node attribute of the A-node that originated it.
import networkx as nx
def main():
# Create graph A
a = nx.Graph()
a.add_node(1)
a.add_node(2)
a.add_node(3)
# Create graph B with nodes that are squares of the nodes in A
# Add to each node in A an attribute (b_node)
# to hold the corresponding node in B
b = nx.Graph()
for node in a:
a.add_node(node, b_node=node * node)
b.add_node(node * node)
print("A:")
print(a.nodes.data())
print("\nB:")
print(b.nodes.data())
if __name__ == '__main__':
main()
Output:
A:
[(1, {'b_node': 1}), (2, {'b_node': 4}), (3, {'b_node': 9})]
B:
[(1, {}), (4, {}), (9, {})]

Related

NetworkX isomorphic connected components

I am solving a specific problem, I would appreciate any suggestions you had for this problem, its trivial but I am not sure if this is the best way to solve this problem.
The Problem: Given a graph G, lets say you get a set of connected component subgraphs {C_1, C_2, ....., C_N}. Now partition the aforementioned set into K subsets such that every element in the subset are isomorphic with each-other. You can have atmost N subsets.
The Solution:
Run a find connected sugraphs. This will return all the connected components as graphs.
Partition this connected components subgraphs based on number of nodes (Which should be fine in our case). Optional
For the subgraphs. Run the following:
Initialize a dictionary with the following. A random node as the key and a singleton set containing the graph itself as its value and add remaining nodes to a deque.
For the remaining nodes:
pop the element in the front of the deque. If there's an isomorphism match add that graph to the dictionary of subgraph, else push the element to its back.
Once there's absolute certainity that we have reached a cycle. I.e. we are scanning the same element which we pushed to the back of the queue. This node's cycle is done. Pop the front of the queue and add the <graph:set([graph])> entry to the dictionary mentioned before. Repeat until there are elements left in the queue.
Can this be further otpimized?
import networkx as nx
nx_graph = nx.Graph()
edges = [
(1, 2),
(2, 3),
(3, 4),
(5, 6),
(6, 7),
(7, 8),
(9, 10),
(10, 11),
(10, 12)
]
for edge in edges:
nx_graph.add_edge(edge[0], edge[1])
nx.draw(nx_graph, pos=nx.spring_layout(nx_graph), node_color='#1ab2c3', with_labels=True)
Graph:
from collections import deque
def paritition_isomorphic_subgraphs(graph):
subgraphs_gen = (graph.subgraph(c) for c in nx.connected_components(graph))
subgraphs_list = list(subgraphs_gen)
graph_queue = deque(subgraphs_list)
graph_of_interest = graph_queue.popleft()
isomprohic_elements = {
graph_of_interest: set([graph_of_interest])
}
last_element_popped = None
count = 0
first_mismatch = None
while graph_queue:
if graph_queue[0] == first_mismatch:
count = 0
graph_of_interest = graph_queue.popleft()
isomprohic_elements[graph_of_interest] = set([graph_of_interest])
if graph_queue:
graph = graph_queue.popleft()
if nx.is_isomorphic(graph_of_interest, graph):
isomprohic_elements[graph_of_interest].add(graph)
else:
if count == 0:
first_mismatch = graph
graph_queue.append(graph)
count += 1
return list(isomprohic_elements.values())

Get networkx subgraph containing a certain number of nodes

I have a networkx DiGraph and I want to extract the subgraph that contains a certain number of nodes.
For example, the Digraph is 0-1-2-3-4-5. I want to obtain all the subgraphs that contains 3 nodes. The result should be: 0-1-2, 1-2-3, 2-3-4, 3-4-5.
How can I do that?
I'm not completely sure if I understand correctly: Your example implies that you only want connected subgraphs? In a directed graph there's more than one kind of connectivity (weak and strong). So you have to decide which one you're looking for.
This might work:
import networkx as nx
from itertools import combinations
# The graph in your example (as I understand it)
G = nx.DiGraph((i, i+1) for i in range(5))
num_of_nodes = 3 # Number of nodes in the subgraphs (here 3, as in your example)
subgraphs = [] # List for collecting the required subgraphs
for nodes in combinations(G.nodes, num_of_nodes):
G_sub = G.subgraph(nodes) # Create subgraph induced by nodes
# Check for weak connectivity
if nx.is_weakly_connected(G_sub):
subgraphs.append(G_sub)
combinations(G.nodes, num_of_nodes) iterates over all unique combinations of num_of_nodes many nodes from G.
The selected subgraphs are exactly the ones you mentioned:
print([H.nodes for H in subgraphs])
print([H.edges for H in subgraphs])
shows
[NodeView((0, 1, 2)), NodeView((1, 2, 3)), NodeView((2, 3, 4)), NodeView((3, 4, 5))]
[OutEdgeView([(0, 1), (1, 2)]), OutEdgeView([(1, 2), (2, 3)]), OutEdgeView([(2, 3), (3, 4)]), OutEdgeView([(3, 4), (4, 5)])]
If your graph is
G = nx.DiGraph([(i, i+1) for i in range(5)] + [(i+1, i) for i in range(5)])
and you're looking for strong connectivity then you have to use
...
# Check for strong connectivity
if nx.is_strongly_connected(G_sub):
...
(The usual warning: G.subgraph() only gives you a view.)

Networkx: How to remove single direction edges?

Suppose I have edges between [(1,2),(2,1),(1,3)], how can I remove (1,3) since it is not bidrectional like the edge between 1 and 2?
I'm assuming this is a DiGraph. In that case, first find the edges you want to remove. Then remove them.
to_remove = [(v,u) for v,u in G.edges() if not G.has_edge(u,v)]
G.remove_edges_from(to_remove)
The list to_remove has all those edges in G for which G does not have the opposite edge (it is a list comprehension).
This one is a little more lengthy, but don't modify the edges directly
import networkx as nx
# create the graph
G = nx.DiGraph()
G.add_edges_from([(1,2),(2,1),(1,3),(4,1),(1,5),(1,6),(5,1)])
H = nx.difference(G.to_undirected().to_directed(), G) # get the uni-directional edges
G = nx.difference(G, H.to_undirected()) # get the difference graph
G.edges()
# [(1, 2), (1, 5), (2, 1), (5, 1)]

How to get the data for the edge between two nodes?

I want to get the edge between two nodes in a networkx graph. More specifically, I want to get some data associated with this edge. I know a priori that these two nodes are linked. Is there a function to do this?
The edge data are stored in a dictionary. To access that dictionary, use get_edge_data().
import networkx as nx
G=nx.Graph()
G.add_edge(1,2, weight=5)
G.get_edge_data(1,2)
> {'weight': 5}
If you want to iterate through all the edges you can use G.edges(data=True)
H = nx.Graph()
H.add_edge(2, 3, color = 'red')
H.add_edge(1, 2, weight = 4)
for u,v,data in H.edges(data=True):
print(u, v, data)
> 1 2 {'weight': 4}
> 2 3 {'color': 'red'}

partition graph into sungraphs based on node's attribute NetworkX

I'm using Networkx to compute some measures of a graph such as diameter, clustering coefficient, etc. It's straight forward how to do this for graph as a whole. What I'm interested in is finding these measures between nodes that have same attribute(say color). I'm thinking if I could partition the graph into different sub graphs, where nodes in each sub graph are of the same color, then I could accomplish go ahead and measure diameter in this sub graph. So my question is: Is there a way to partition a graph into sub graphs which contain nodes of same color?
I would really appreciate any insight.
Use Graph.subgraph(nodes)
NetworkX 2.x+:
Demo
import networkx as nx
G = nx.Graph()
G.add_nodes_from([1, 2, 3], color="red")
G.add_nodes_from([4, 5, 6])
G.nodes # NodeView((1, 2, 3, 4, 5, 6))
# create generator
nodes = (
node
for node, data
in G.nodes(data=True)
if data.get("color") == "red"
)
subgraph = G.subgraph(nodes)
subgraph.nodes # NodeView((1, 2, 3))
older NetworkX's
Iterate over (Graph.iter_nodes()) and filter the nodes based on your criteria. Pass that list to Graph.subgraph() and it'll return a copy of those nodes and their internal edges.
For example:
G = nx.Graph()
# ... build or do whatever to the graph
nodes = (n for n, d in G.nodes_iter(data=True)) if d.get('color') == 'red')
subgraph = G.subgraph(nodes)

Categories