繁体   English   中英

我们如何从 GV 文件创建具有非重叠子图的 GV 文件?

[英]How do we create GV files with non-overlapping subgraphs from a GV file?

图形

我有一个包含 3 个子图的 GV 文件:

  1. cluster_1
  2. cluster_2
  3. 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

通缉

我希望创建子图不重叠的其他 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 图形。

PyGraphviz

先决条件:必须在您的系统上安装graphviz二进制文件。 使用 pip 安装 Python package:

pip install pygraphviz

请参阅 安装 — PyGraphviz 1.10 文档

去除重叠子图

注意:除了从源字符串加载之外,您还可以将文件句柄或文件名作为参数传递给构造函数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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM