如何写GraphViz的子图与升压:: write_graphviz [英] how to write GraphViz subgraphs with boost::write_graphviz
问题描述
是否有可能使用生成一个DOT子 ::的boost :: write_graphviz
?
例如,如果我在一个图G创建一个子G0,我能得到的东西像DOT输出以下内容:
图G {
子G0 {
...
}
...
}
我终于想通了两个子图是如何工作的和的如何使用的boost :: write_graphviz
实际打印这些。
第一个要求是半记载在Boost库源$ C $ C注释: 要求graph_name财产
的
最令人惊讶的要求,但似乎是详细:: write_graphviz_subgraph
假定的presence
-
vertex_attribute
-
edge_attribute
-
graph_vertex_attribute
,graph_edge_attribute
,graph_graph_attribute
图形属性
属性。我倒是觉得这些要求可以说是相当严格的,因为你的图表类型看起来至少是这样的:
使用图形=
的adjacency_list<血管内皮细胞,血管内皮细胞,directedS,
财产< vertex_attribute_t,GraphvizAttributes>中
财产< edge_index_t,INT,财产和LT; edge_attribute_t,GraphvizAttributes> >中
财产< graph_name_t,标准::字符串,
财产< graph_graph_attribute_t,GraphvizAttributes,
财产< graph_vertex_attribute_t,GraphvizAttributes,
财产< graph_edge_attribute_t,GraphvizAttributes>
> > >
取代;
不管怎么说,这是很好的演示如何使用这些实际供应EDGE /节点/(分)图形属性Graphviz的,当然是:
<大骨节病> 住在Coliru 骨节病>
模板&LT; typename的子&GT;子create_data()
{
枚举{A,B,C,D,E,F,N}; //主刃
主要子(N); 子和放大器; SUB1 = main.create_subgraph();
子和放大器; SUB2 = main.create_subgraph(); 汽车A1 = add_vertex(A,SUB1);
汽车B1 = add_vertex(B,SUB1); 汽车E2 = add_vertex(E,SUB2);
汽车C2 = add_vertex(C,SUB2);
汽车F2 = add_vertex(F,SUB2); 的add_edge(A1,B1,SUB1);
的add_edge(E2,F2,SUB2);
的add_edge(C2,F2 SUB2); 的add_edge(E,B,主);
的add_edge(B,C,主要的);
的add_edge(B,D,主);
的add_edge(F,D,主); //设置一些图形即属性
get_property(主,graph_name)=G0;
get_property(SUB1,graph_name)=clusterG1;
get_property(SUB2,graph_name)=clusterG2; get_property(SUB1,graph_graph_attribute)[标签] =G1;
/ * *额外/ get_property(SUB1,graph_vertex_attribute)[形] =Mrecord; get_property(SUB2,graph_graph_attribute)[标签] =G2;
/ * *额外/ get_property(SUB1,graph_vertex_attribute)色] =红;
/ * *额外/ get_property(SUB2,graph_graph_attribute)[填充颜色] =浅灰色;
/ * *额外/ get_property(SUB2,graph_graph_attribute)风格] =装;
/ * *额外/ get_property(SUB2,graph_vertex_attribute)[形] =圈; 返回主;
}
这与
INT的main(){
#IFDEF GENERATE_RANDOM_GRAPHS
write_graphviz(标准::法院,generate_random&LT;&子LT;曲线&GT;&GT;());
#其他
CHAR名称[] = {ABCDEFGH};
write_graphviz(标准::法院,create_data&LT;&子LT;曲线&GT;&GT;(),make_iterator_vertex_map(地名));
#万一
}
我也实施 generate_random
为我自己的测试和了解,并产生像图:
完整的程序
<大骨节病> 住在Coliru 骨节病>
的#include&LT;升压/图/ graphviz.hpp&GT;
#包括LT&;升压/图/ adjacency_list.hpp&GT;
#包括LT&;升压/图/ subgraph.hpp&GT;
#包括LT&;&iostream的GT;#包括LT&;升压/图/ random.hpp&GT; //如果你注释掉随机图创作code
#包括LT&;随机的GT;使用名字空间boost;模板&LT; typename的子&GT;子generate_random()
{
的std :: mt19937 PRNG(性病:: random_device {}());
子随机(uniform_int&LT; INT&GT;(10,20)(PRNG)); 自动潜艇= uniform_int&LT; INT&GT;(1,5)(PRNG);
而(subs--)randomized.create_subgraph();
潜艇=的boost ::大小(randomized.children()); INT偏移= 0;
为(自动&安培;子:make_iterator_range(randomized.children()))
{
用于(为size_t I =偏移; I&LT;为num_vertices(随机); I + =潜艇)
add_vertex(ⅰ,分);
++抵消;
} 汽车random_edges = [&放大器;(子&安培; G){
uniform_int&LT; typename的子:: vertex_descriptor的&GT; V(0,为num_vertices(G)-1);
为(为size_t I = 1; I&4; ++ⅰ)
的add_edge(ⅴ(PRNG),V(PRNG),G);
}; 为(自动&安培;子:make_iterator_range(randomized.children()))
random_edges(次);
random_edges(随机); //设置一些图形即属性
get_property(随机,graph_name)=G0; 偏移量= 0;
为(自动&安培;子:make_iterator_range(randomized.children())){
++抵消;
get_property(分,graph_name)=集群+的std :: to_string(补偿);
get_property(分,graph_graph_attribute)[标签] =G+的std :: to_string(补偿);
} 返回随机;
}模板&LT; typename的子&GT;子create_data()
{
枚举{A,B,C,D,E,F,N}; //主刃
主要子(N); 子和放大器; SUB1 = main.create_subgraph();
子和放大器; SUB2 = main.create_subgraph(); 汽车A1 = add_vertex(A,SUB1);
汽车B1 = add_vertex(B,SUB1); 汽车E2 = add_vertex(E,SUB2);
汽车C2 = add_vertex(C,SUB2);
汽车F2 = add_vertex(F,SUB2); 的add_edge(A1,B1,SUB1);
的add_edge(E2,F2,SUB2);
的add_edge(C2,F2 SUB2); 的add_edge(E,B,主);
的add_edge(B,C,主要的);
的add_edge(B,D,主);
的add_edge(F,D,主); //设置一些图形即属性
get_property(主,graph_name)=G0;
get_property(SUB1,graph_name)=clusterG1;
get_property(SUB2,graph_name)=clusterG2; get_property(SUB1,graph_graph_attribute)[标签] =G1;
/ * *额外/ get_property(SUB1,graph_vertex_attribute)[形] =Mrecord; get_property(SUB2,graph_graph_attribute)[标签] =G2;
/ * *额外/ get_property(SUB1,graph_vertex_attribute)色] =红;
/ * *额外/ get_property(SUB2,graph_graph_attribute)[填充颜色] =浅灰色;
/ * *额外/ get_property(SUB2,graph_graph_attribute)风格] =装;
/ * *额外/ get_property(SUB2,graph_vertex_attribute)[形] =圈; 返回主;
}使用GraphvizAttributes =
性病::地图&LT;的std ::字符串,性病::字符串取代;使用图形=
的adjacency_list&LT;血管内皮细胞,血管内皮细胞,directedS,
财产&LT; vertex_attribute_t,GraphvizAttributes&gt;中
财产&LT; edge_index_t,INT,财产和LT; edge_attribute_t,GraphvizAttributes&GT; &gt;中
财产&LT; graph_name_t,标准::字符串,
财产&LT; graph_graph_attribute_t,GraphvizAttributes,
财产&LT; graph_vertex_attribute_t,GraphvizAttributes,
财产&LT; graph_edge_attribute_t,GraphvizAttributes&GT;
&GT; &GT; &GT;
取代;诠释主(){
#IFDEF GENERATE_RANDOM_GRAPHS
write_graphviz(标准::法院,generate_random&LT;&子LT;曲线&GT;&GT;());
#其他
CHAR名称[] = {ABCDEFGH};
write_graphviz(标准::法院,create_data&LT;&子LT;曲线&GT;&GT;(),make_iterator_vertex_map(地名));
#万一
}
Is it possible to generate a DOT subgraph using ::boost::write_graphviz
?
For instance, if I create a subgraph G0 in a graph G, can I get something like the following in the DOT output:
graph G {
subgraph G0 {
...
}
...
}
I finally figured out both how subgraphs work and how to use boost::write_graphviz
to actually print these.
The first requirement is "semi-documented" in a comment in the boost library source code: requires graph_name property
.
The most surprising requirement however seemed to be that detail::write_graphviz_subgraph
assumes the presence of
vertex_attribute
edge_attribute
graph_vertex_attribute
,graph_edge_attribute
,graph_graph_attribute
graph properties
properties. I'd think these requirements can be quite restrictive, because your graph type would look at least like this:
using Graph =
adjacency_list<vecS, vecS, directedS,
property<vertex_attribute_t, GraphvizAttributes>,
property<edge_index_t, int, property<edge_attribute_t, GraphvizAttributes> >,
property<graph_name_t, std::string,
property<graph_graph_attribute_t, GraphvizAttributes,
property<graph_vertex_attribute_t, GraphvizAttributes,
property<graph_edge_attribute_t, GraphvizAttributes>
> > >
>;
Anyways, it's nice to demonstrate how to use those to actually supply edge/node/(sub)graph attributes to Graphviz, of course:
template <typename SubGraph> SubGraph create_data()
{
enum { A,B,C,D,E,F,N }; // main edges
SubGraph main(N);
SubGraph& sub1 = main.create_subgraph();
SubGraph& sub2 = main.create_subgraph();
auto A1 = add_vertex(A, sub1);
auto B1 = add_vertex(B, sub1);
auto E2 = add_vertex(E, sub2);
auto C2 = add_vertex(C, sub2);
auto F2 = add_vertex(F, sub2);
add_edge(A1, B1, sub1);
add_edge(E2, F2, sub2);
add_edge(C2, F2, sub2);
add_edge(E, B, main);
add_edge(B, C, main);
add_edge(B, D, main);
add_edge(F, D, main);
// setting some graph viz attributes
get_property(main, graph_name) = "G0";
get_property(sub1, graph_name) = "clusterG1";
get_property(sub2, graph_name) = "clusterG2";
get_property(sub1, graph_graph_attribute)["label"] = "G1";
/*extra*/get_property(sub1, graph_vertex_attribute)["shape"] = "Mrecord";
get_property(sub2, graph_graph_attribute)["label"] = "G2";
/*extra*/get_property(sub1, graph_vertex_attribute)["color"] = "red";
/*extra*/get_property(sub2, graph_graph_attribute)["fillcolor"] = "lightgray";
/*extra*/get_property(sub2, graph_graph_attribute)["style"] = "filled";
/*extra*/get_property(sub2, graph_vertex_attribute)["shape"] = "circle";
return main;
}
That's with
int main() {
#ifdef GENERATE_RANDOM_GRAPHS
write_graphviz(std::cout, generate_random<subgraph<Graph> >());
#else
char names[] = {"ABCDEFGH"};
write_graphviz(std::cout, create_data<subgraph<Graph> >(), make_iterator_vertex_map(names));
#endif
}
I've also implemented generate_random
for my own testing and understanding, and it generates graphs like:
Full Program
#include <boost/graph/graphviz.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/subgraph.hpp>
#include <iostream>
#include <boost/graph/random.hpp> // in case you comment out the random graph creation code
#include <random>
using namespace boost;
template <typename SubGraph> SubGraph generate_random()
{
std::mt19937 prng(std::random_device{}());
SubGraph randomized(uniform_int<int>(10,20)(prng));
auto subs = uniform_int<int>(1,5)(prng);
while (subs--) randomized.create_subgraph();
subs = boost::size(randomized.children());
int offset = 0;
for (auto& sub : make_iterator_range(randomized.children()))
{
for (size_t i = offset; i < num_vertices(randomized); i += subs)
add_vertex(i, sub);
++offset;
}
auto random_edges = [&](SubGraph& g) {
uniform_int<typename SubGraph::vertex_descriptor> v(0, num_vertices(g) -1);
for (size_t i = 1; i < 4; ++i)
add_edge(v(prng), v(prng), g);
};
for (auto& sub : make_iterator_range(randomized.children()))
random_edges(sub);
random_edges(randomized);
// setting some graph viz attributes
get_property(randomized, graph_name) = "G0";
offset = 0;
for (auto& sub : make_iterator_range(randomized.children())) {
++offset;
get_property(sub, graph_name) = "cluster" + std::to_string(offset);
get_property(sub, graph_graph_attribute)["label"] = "G" + std::to_string(offset);
}
return randomized;
}
template <typename SubGraph> SubGraph create_data()
{
enum { A,B,C,D,E,F,N }; // main edges
SubGraph main(N);
SubGraph& sub1 = main.create_subgraph();
SubGraph& sub2 = main.create_subgraph();
auto A1 = add_vertex(A, sub1);
auto B1 = add_vertex(B, sub1);
auto E2 = add_vertex(E, sub2);
auto C2 = add_vertex(C, sub2);
auto F2 = add_vertex(F, sub2);
add_edge(A1, B1, sub1);
add_edge(E2, F2, sub2);
add_edge(C2, F2, sub2);
add_edge(E, B, main);
add_edge(B, C, main);
add_edge(B, D, main);
add_edge(F, D, main);
// setting some graph viz attributes
get_property(main, graph_name) = "G0";
get_property(sub1, graph_name) = "clusterG1";
get_property(sub2, graph_name) = "clusterG2";
get_property(sub1, graph_graph_attribute)["label"] = "G1";
/*extra*/get_property(sub1, graph_vertex_attribute)["shape"] = "Mrecord";
get_property(sub2, graph_graph_attribute)["label"] = "G2";
/*extra*/get_property(sub1, graph_vertex_attribute)["color"] = "red";
/*extra*/get_property(sub2, graph_graph_attribute)["fillcolor"] = "lightgray";
/*extra*/get_property(sub2, graph_graph_attribute)["style"] = "filled";
/*extra*/get_property(sub2, graph_vertex_attribute)["shape"] = "circle";
return main;
}
using GraphvizAttributes =
std::map<std::string, std::string>;
using Graph =
adjacency_list<vecS, vecS, directedS,
property<vertex_attribute_t, GraphvizAttributes>,
property<edge_index_t, int, property<edge_attribute_t, GraphvizAttributes> >,
property<graph_name_t, std::string,
property<graph_graph_attribute_t, GraphvizAttributes,
property<graph_vertex_attribute_t, GraphvizAttributes,
property<graph_edge_attribute_t, GraphvizAttributes>
> > >
>;
int main() {
#ifdef GENERATE_RANDOM_GRAPHS
write_graphviz(std::cout, generate_random<subgraph<Graph> >());
#else
char names[] = {"ABCDEFGH"};
write_graphviz(std::cout, create_data<subgraph<Graph> >(), make_iterator_vertex_map(names));
#endif
}
这篇关于如何写GraphViz的子图与升压:: write_graphviz的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!