how to append 2 graphs (graph1 and graph2) using pydot in python - python

I generate a pydot graph with the following code
graph1 = pydot.Dot(graph_type='digraph')
A = pydot.Node("A", style="filled", fillcolor="green")
B = pydot.Node("B", style="filled", fillcolor="blue")
graph1.add_node(A)
graph1.add_node(B)
graph1.add_edge(pydot.Edge(A,B))
graph1.write_png('graph1.png')
and my output is
and I generate a another pydot graph with the following code
graph2 = pydot.Dot(graph_type='digraph')
C = pydot.Node("C", style="filled", fillcolor="green")
D = pydot.Node("D", style="filled", fillcolor="blue")
graph2.add_node(C)
graph2.add_node(D)
graph2.add_edge(pydot.Edge(C,D))
graph2.write_png('graph2.png')
and my output is as follows.
My request is how to merge these 2 graphs(graph1 and graph2)?
My expected output after merging as
I tried with the following code, but, its not working..
graph3 = pydot.Dot(graph_type='digraph')
graph1_leaf = pydot.Node(graph1.get_node(B), style="filled",
fillcolor="green")
graph2_root = pydot.Node(graph2.get_node(C), style="filled",
fillcolor="green")
graph3.add_node(graph1_leaf)
graph3.add_node(graph2_root)
graph3.add_edge(pydot.Edge(graph1_leaf,graph2_root))
graph3.write_png('graph3.png')
Please guide me to merge these 2 graphs using pydot in python.. Thanks in advance..

I couldn't find documentation describing joining 2 graphs. the common practice seems to be joining 2 sub graphs (clusters).
Here is answer that shows how it's done:
Edges between two subgraphs in pydot
another helpful answer:
Merge two dot graphs at a common node in python
Update, answer for edited question:
a few issues with your code:
graph1.get_node(B) returns a list of nodes
you are adding only the nodes and edge for connecting the graphs while you want all other nodes and edges
This code should return your wanted result:
graph3 = pydot.Dot(graph_type='digraph')
for node in graph1.get_nodes():
graph3.add_node(node)
for node in graph2.get_nodes():
graph3.add_node(node)
for edge in graph1.get_edges():
graph3.add_edge(edge)
for edge in graph2.get_edges():
graph3.add_edge(edge)
node_graph1 = graph1.get_node('B')[0]
node_graph2 = graph2.get_node('C')[0]
graph3.add_edge(pydot.Edge(node_graph1,node_graph2))
graph3.write_png('/tmp/graph3.png')
hope it helps.

Related

Create "short cut" aware graph in Python

Assume we have these sequences:
A->X->Y->Z
B->Y->Z
C->Y->Z
D->X->Z
I would like to create a graph like:
C
|
A-X-Y-Z
| |
D B
In the sequence D-X-Z there is a short cut. My goal is to create a directed acyclic graph by eliminating these short-cuts and vice versa, expand existing edges when encountering expanded paths (e.g.: X-Z with X-Y-Z).
My approach so far was to create a directed graph with Networkx but this does not solve the problem because I could not find a way to eliminate short circuits (it is a big graph with hundreds of thousands of nodes).
Any hints would be appreciated.
You can set up the graph:
import networkx as nx
text = '''
A-X-Y-Z
B-Y-Z
C-Y-Z
D-X-Z
'''
G = nx.Graph()
for s in text.strip().split('\n'):
l = s.split('-')
G.add_edges_from(zip(l,l[1:]))
Then use find_cycles and remove_edge repeatedly to identify and remove edges that form cycles:
while True:
try:
c = nx.find_cycle(G)
print(f'found cycle: {c}')
G.remove_edge(*c[0])
except nx.NetworkXNoCycle:
break

Problem with appending a graph object to lists for networkx in Python

I am trying to remove nodes at random from graphs using the networkx package. The first block describes the graph construction and the second block gives me the node lists that I have to remove from my graph H (20%, 50% and 70% removals). I want 3 versions of the base graph H in the end, in a list or any data structure. The code in block 3 gives me objects of type "None". The last block shows that it works for a single case.
I am guessing that the problem is in the append function, which somehow returns objects of type "None". I also feel that the base graph H might be getting altered after every iteration. Is there any way around this? Any help would be appreciated :)
import networkx as nx
import numpy as np
import random
# node removals from Graphs at random
# network construction
H = nx.Graph()
H.add_nodes_from([1,2,3,4,5,6,7,8,9,10])
H.add_edges_from([[1,2],[2,4],[5,6],[7,10],[1,5],[3,6]])
nx.info(H)
nodes_list = list(H.nodes)
# list of nodes to be removed
perc = [.20,.50,.70] # percentage of nodes to be removed
random_sample_list = []
for p in perc:
interior_list = []
random.seed(2) # for replicability
sample = round(p*10)
random_sample = random.sample(nodes_list, sample)
interior_list.append(random_sample)
random_sample_list.append(random_sample)
# applying the list of nodes to be removed to create a list of graphs - not working
graph_list = []
for i in range(len(random_sample_list)):
H1 = H.copy()
graph_list.append(H1.remove_nodes_from(random_sample_list[i]))
# list access - works
H.remove_nodes_from(random_sample_list[1])
nx.info(H)
Final output should look like:
[Graph with 20% removed nodes, Graph with 50% removed nodes, Graph with 7% removed nodes] - eg. list
The function remove_nodes_from does not return the modified graph, but returns None. Consequently, you only need to create the graph with the desired percentage of your nodes and append it to the list:
graph_list = []
for i in range(len(random_sample_list)):
H1 = H.copy()
H1.remove_nodes_from(random_sample_list[i])
graph_list.append(H1)

How to find all connected subgraph of a graph in networkx?

I'm developing a python application, and i want to list all possible connected subgraph of any size and starting from every node using NetworkX.
I just tried using combinations() from itertools library to find all possible combination of nodes but it is very too slow because it searchs also for not connected nodes:
for r in range(0,NumberOfNodes)
for SG in (G.subgraph(s) for s in combinations(G,r):
if (nx.is_connected(SG)):
nx.draw(SG,with_labels=True)
plt.show()
The actual output is correct. But i need another way faster to do this, because all combinations of nodes with a graph of 50 nodes and 8 as LenghtTupleToFind are up to 1 billion (n! / r! / (n-r)!) but only a minimal part of them are connected subgraph so are what i am interested in. So, it's possible to have a function for do this?
Sorry for my english, thank you in advance
EDIT:
As an example:
so, the results i would like to have:
[0]
[0,1]
[0,2]
[0,3]
[0,1,4]
[0,2,5]
[0,2,5,4]
[0,1,4,5]
[0,1,2,4,5]
[0,1,2,3]
[0,1,2,3,5]
[0,1,2,3,4]
[0,1,2,3,4,5]
[0,3,2]
[0,3,1]
[0,3,2]
[0,1,4,2]
and all combination that generates a connected graph
I had the same requirements and ended up using this code, super close to what you were doing. This code yields exactly the input you asked for.
import networkx as nx
import itertools
G = you_graph
all_connected_subgraphs = []
# here we ask for all connected subgraphs that have at least 2 nodes AND have less nodes than the input graph
for nb_nodes in range(2, G.number_of_nodes()):
for SG in (G.subgraph(selected_nodes) for selected_nodes in itertools.combinations(G, nb_nodes)):
if nx.is_connected(SG):
print(SG.nodes)
all_connected_subgraphs.append(SG)
I have modified Charly Empereur-mot's answer by using ego graph to make it faster:
import networkx as nx
import itertools
G = you_graph.copy()
all_connected_subgraphs = []
# here we ask for all connected subgraphs that have nb_nodes
for n in you_graph.nodes():
egoG = nx.generators.ego_graph(G,n,radius=nb_nodes-1)
for SG in (G.subgraph(sn+(n,) for sn in itertools.combinations(egoG, nb_nodes-1)):
if nx.is_connected(SG):
all_connected_subgraphs.append(SG)
G.remove_node(n)
You might want to look into connected_components function. It will return you all connected nodes, which you can then filter by size and node.
You can find all the connected components in O(n) time and memory complexity. Keep a seen boolean array, and run Depth First Search (DFS) or Bread First Search (BFS), to find the connected components.
In my code, I used DFS to find the connected components.
seen = [False] * num_nodes
def search(node):
component.append(node)
seen[node] = True
for neigh in G.neighbors(node):
if not seen[neigh]:
dfs(neigh)
all_subgraphs = []
# Assuming nodes are numbered 0, 1, ..., num_nodes - 1
for node in range(num_nodes):
component = []
dfs(node)
# Here `component` contains nodes in a connected component of G
plot_graph(component) # or do anything
all_subgraphs.append(component)

graphviz Python Node Shapes-Pie Chart in a node

I am writing a Python script to generate a network graph using graphviz. Some of my nodes represents injection into a network and I am wondering if it is possible to have a Pie-Chart inside some of the nodes.
Python code for a simple two node network is following:
import graphviz as gv
g1 = gv.Graph(format='svg')
g1.node('A')
g1.node('B')
g1.edge('A', 'B')
filename = g1.render(filename='img/g1')
I let the PyGraphViz implementation up to you. But to answer to the core of your question, since graphviz 2.30, you can use the wedged style for nodes, to achieve the desired result. Here is an example in plain dot:
digraph G {
{
node [shape=circle style=wedged fillcolor="red;0.3:green;0.6:orange"]
A
node [style=solid fillcolor="white" ]
B
C
}
B -> A
B -> C
}
The list of colors is expressed as a colon separated list. The value after the **semi-colon* in the weight of the given color. The sum of all weights must be equal to 1.0. See the colorList attribute

How to add nodes and edges while setting their keys using for loops?

I am new to python and i need to solve a problem using min_cost_flow, my question may seem rudimentary but i was wondering how i can use for loops to name my nodes and edges something like:
for cp in range (1,50):
G.add_node(cp, demand[cp-1])
I assumed a demand list where the name of the nodes to be created are stored. here is the code for doing it:
g=nx.Graph()
demands = ['d_1','d_2','d_3']
for i in xrange(3):
g.add_node(demands[i])
nx.draw(g,with_labels = True, node_size = 500)
plt.show()
Attached is the resulting graph.

Categories

Resources