![](/img/trans.png)
[英]How to create Digraph from preconstructed .gv file with Graphviz via python?
[英]How do we create GV files with non-overlapping subgraphs from a GV file?
我有一個包含 3 個子圖的 GV 文件:
cluster_1
cluster_2
cluster_3
Final_Graph.gv
的來源:
digraph Final_Graph {
graph [center=true rankdir=LR ratio=compress size="15,10"]
a
b
c
d
a -> b [label = 1]
a -> c [label = 2]
a -> d [label = 3]
b -> d [label = 4]
c -> d [label = 5]
subgraph cluster_1{
color=lightgrey style=filled
label="A"
a
b
}
subgraph cluster_2{
color=lightgrey style=filled
label="B"
a
b
}
subgraph cluster_3{
color=lightgrey style=filled
label="C"
c
d
}
}
渲染:
我希望創建子圖不重疊的其他 GV 文件(即沒有相似節點的子圖,因此對於這種情況,第一個文件可以有簇 1 和 3,第二個文件可以有簇 2 和 3)。
我在 Python 中使用這個 function 來完成這個任務:
import networkx as nx
import itertools
def draw_graph_combinations():
# Load the original graph
G = nx.drawing.nx_agraph.read_dot("Final_Graph.gv")
# Create an empty dictionary to store the subgraphs
subgraphs = {}
# Iterate over the edges of the graph
for u, v, data in G.edges(data=True):
label = data.get("label")
if label not in subgraphs:
subgraphs[label] = nx.DiGraph()
for node in G.nodes:
# Add the node to each subgraph
for label, subgraph in subgraphs.items():
subgraph.add_node(node)
for label, subgraph in subgraphs.items():
for edge in G.edges:
subgraph.add_edge(edge[0], edge[1])
# Get all combinations of subgraphs
combinations = itertools.combinations(subgraphs.items(), len(subgraphs))
# Iterate over the combinations
for i, subgraph_items in enumerate(combinations):
combined_subgraph = nx.DiGraph()
for label, subgraph in subgraph_items:
combined_subgraph = nx.compose(combined_subgraph, subgraph)
nx.drawing.nx_agraph.write_dot(combined_subgraph, f"combined_subgraph_{i}.gv")
但是,當我在 Python 中運行這個 function 時,打印出來的文件只包含原始文件的節點和邊,沒有顯示子圖。
Python有什么方法可以把這個GV文件分成子圖不重疊的其他文件嗎?
我嘗試使用 PyGraphviz (1.10) 刪除子圖(類似於下面@hc_dev 的回答),但是刪除方法找不到子圖(cluster_1 和 cluster_2)。 我還想找到一種方法來找到非重疊子圖的組合並將結果粘貼到新文件中。 這是我當前的代碼版本:
G = pgv.AGraph("Final_Graph.gv")
combinations = itertools.combinations(G.subgraphs(), 2)
for index, subgraph in enumerate(combinations):
if index == 0:
continue
if any(i in subgraph[1] for i in subgraph[0]):
G.remove_subgraph(subgraph[1].name)
G.write(f"new_file{index}.gv")
但是,我沒有從這段代碼中得到任何 GV 文件,而且我從這段代碼中得到的文件和另一個 GV 文件仍然有重疊的子圖。 您對如何解決此問題有任何想法嗎?
您可以使用 package PyGraphviz讀取、修改、編寫和渲染 Graphviz 圖形。
先決條件:必須在您的系統上安裝graphviz
二進制文件。 使用 pip 安裝 Python package:
pip install pygraphviz
注意:除了從源字符串加載之外,您還可以將文件句柄或文件名作為參數傳遞給構造函數AGraph(filename='Final_Graph.gv')
或AGraph('Final_Graph.gv')
。
import pygraphviz as pgv
import itertools
s = '''digraph Final_Graph {
graph [center=true rankdir=LR ratio=compress size="15,10"]
a
b
c
d
a -> b [label = 1]
a -> c [label = 2]
a -> d [label = 3]
b -> d [label = 4]
c -> d [label = 5]
subgraph cluster_1{
color=lightgrey style=filled
label="A"
a
b
}
subgraph cluster_2{
color=lightgrey style=filled
label="B"
a
b
}
subgraph cluster_3{
color=lightgrey style=filled
label="C"
c
d
}
}'''
# print some information of the parsed graph
def print_info(G):
print(f"Graph '{G.get_name()}' has:")
print(f"* {len(G.nodes())} nodes")
print(f"* {len(G.edges())} edges")
print(f"* {len(G.subgraphs())} subgraphs")
def combine_subgraphs(G):
combinations = itertools.combinations(G.subgraphs(), 2) # iterator returned
pairs = list(combinations) # store iterator results in a list
return pairs
def overlapping(pair_of_subgraphs):
left_nodes = pair_of_subgraphs[0].nodes()
right_nodes = pair_of_subgraphs[1].nodes()
shared_nodes = set(left_nodes).intersection(set(right_nodes))
return shared_nodes
def remove_subgraph(G, subgraph_name):
# the first file could have clusters 1 and 3
G_copy = G.copy() # Return a copy of the graph.
G_copy.remove_subgraph(subgraph_name) # Remove subgraph with given name.
print(f"## Copy: without {subgraph_name}\n{G_copy.string()}") # Return a string (unicode) representation of graph in dot format.
return G_copy
G = pgv.AGraph(string=s) # loading a graph from source string
print_info(G)
pairs = combine_subgraphs(G)
print(f"Searching for overlapps in {len(pairs)} combinations:")
for i, pair in enumerate(pairs):
if overlapping(pair):
print(f"{i}: Overlapped ❌️")
left_name = pair[0].name
right_name = pair[1].name
print(f"Removing left subgraph: {left_name} ..")
left_removed = remove_subgraph(G, left_name)
#left_removed.write(f"without_{left_name}.dot") # Write graph in dot format to file on path.
print(f"Removing right subgraph: {right_name} ..")
right_removed = remove_subgraph(G, right_name)
#right_removed.write(f"without_{right_name}.dot") # Write graph in dot format to file on path.
else:
print(f"{i}: Non-Overlapping ✔️")
print("Done.")
控制台上的 Output(使用 pygraphviz 1.6 版測試):
Graph 'Final_Graph' has:
* 4 nodes
* 5 edges
* 3 subgraphs
Searching for overlapps in 3 combinations:
0: Overlapped ❌
Removing left subgraph: cluster_1 ..
## Copy: without cluster_1
digraph Final_Graph {
graph [center=true,
rankdir=LR,
ratio=compress,
size="15,10"
];
subgraph cluster_2 {
graph [color=lightgrey,
label=B,
style=filled
];
a;
b;
}
subgraph cluster_3 {
graph [color=lightgrey,
label=C,
style=filled
];
c;
d;
}
a -> b [label=1];
a -> c [label=2];
a -> d [label=3];
b -> d [label=4];
c -> d [label=5];
}
Removing right subgraph: cluster_2 ..
## Copy: without cluster_2
digraph Final_Graph {
graph [center=true,
rankdir=LR,
ratio=compress,
size="15,10"
];
subgraph cluster_1 {
graph [color=lightgrey,
label=A,
style=filled
];
a;
b;
}
subgraph cluster_3 {
graph [color=lightgrey,
label=C,
style=filled
];
c;
d;
}
a -> b [label=1];
a -> c [label=2];
a -> d [label=3];
b -> d [label=4];
c -> d [label=5];
}
1: Non-Overlapping ✔️
2: Non-Overlapping ✔️
Done.
要將刪除結果保存到文件,請取消注釋相應的寫入行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.