[英]How do we create GV files with non-overlapping subgraphs from a GV file?
I am having a GV file containing 3 subgraphs:我有一个包含 3 个子图的 GV 文件:
cluster_1
cluster_2
cluster_3
Source of Final_Graph.gv
: 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
}
}
Rendered:渲染:
I am looking to create other GV files with subgraphs being non-overlapping (that is subgraphs with no similar nodes, so for this case, the first file could have clusters 1 and 3, and the second file could have clusters 2 and 3).我希望创建子图不重叠的其他 GV 文件(即没有相似节点的子图,因此对于这种情况,第一个文件可以有簇 1 和 3,第二个文件可以有簇 2 和 3)。
I am using this function in Python to do this task:我在 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")
However, when I run this function in Python, the files printed out only contains the nodes and edges of the original file, without the subgraphs being shown.但是,当我在 Python 中运行这个 function 时,打印出来的文件只包含原始文件的节点和边,没有显示子图。
Is there any method in Python to divide this GV file into other files with non-overlapping subgraphs? Python有什么方法可以把这个GV文件分成子图不重叠的其他文件吗?
I have tried to use PyGraphviz (1.10) to remove subgraphs (similar to the answer from @hc_dev below), but the remove method could not find the subgraphs (cluster_1 and cluster_2).我尝试使用 PyGraphviz (1.10) 删除子图(类似于下面@hc_dev 的回答),但是删除方法找不到子图(cluster_1 和 cluster_2)。 I also would like to find a way to find combination of non-overlapping subgraphs and paste result in new files.
我还想找到一种方法来找到非重叠子图的组合并将结果粘贴到新文件中。 Here is my current version of the code:
这是我当前的代码版本:
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")
However, I did not get any GV file from this code, and my files that I got from this code with another GV file still have overlapping subgraphs.但是,我没有从这段代码中得到任何 GV 文件,而且我从这段代码中得到的文件和另一个 GV 文件仍然有重叠的子图。 Do you have any ideas on how to fix this problem?
您对如何解决此问题有任何想法吗?
You can use package PyGraphviz for reading, modifying, writing and rendering Graphviz graphs.您可以使用 package PyGraphviz读取、修改、编写和渲染 Graphviz 图形。
Prerequisite: graphviz
binaries have to be installed on your system.先决条件:必须在您的系统上安装
graphviz
二进制文件。 Install the Python package using pip:使用 pip 安装 Python package:
pip install pygraphviz
See Install — PyGraphviz 1.10 documentation .请参阅 安装 — PyGraphviz 1.10 文档。
Note: Instead loading from source string, you can also pass a file-handle or file-name as parameter to constructor AGraph(filename='Final_Graph.gv')
or AGraph('Final_Graph.gv')
.注意:除了从源字符串加载之外,您还可以将文件句柄或文件名作为参数传递给构造函数
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 on console (tested with pygraphviz version 1.6):控制台上的 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.
To save removal-results to files uncomment the respective write-lines.要将删除结果保存到文件,请取消注释相应的写入行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.