如何写GraphViz的子图与升压:: write_graphviz [英] how to write GraphViz subgraphs with boost::write_graphviz

查看:199
本文介绍了如何写GraphViz的子图与升压:: 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:

Live On Coliru

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

Live On Coliru

#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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆