Search code examples
c++vertexboost-graph

Boost Graph Library, fix node size


I am constructing graph with Boost Graph Library and Graphviz. In my code, I have a class that export a Graph to a .dot format. I setup the properties of the graph with the following lines:

dynamic_properties dp;

dp.property("rankdir", boost::make_constant_property<Graph*>(std::string("TB")));
dp.property("node_id", get(&VertexP::tag, m_graph));
dp.property("label", get(&VertexP::tag, m_graph));
dp.property("shape", get(&VertexP::shape, m_graph));
dp.property("style", get(&VertexP::style, m_graph));
dp.property("pos", get(&VertexP::pos, m_graph));
dp.property("label", get(&ArrowP::symbol, m_graph));
dp.property("color", get(&ArrowP::color, m_graph));
dp.property("style", get(&ArrowP::style, m_graph));
write_graphviz_dp(ss, m_graph, dp);

I am trying to use the fixedsize keyword of graphviz and the width and height keywords to fix the size of my node (they have different sizes depending on the quantity of text in the label).

I would like to setup it from the dp.property method. The objective being to add the following line in my .dot document:

node [ fixedsize = true, width = 1.1, height = 1.1]

I have tried the following but it does not work:

dp.property("fixedsize", boost::make_constant_property<VertexP*>(std::string("true")));
dp.property("width", boost::make_constant_property<VertexP*>(std::string("1")));
dp.property("height", boost::make_constant_property<VertexP*>(std::string("1")));

Do you know how I can set the attribute fixedsize to my vertex in my dot file from dp.property.


Solution

  • In the property maps, the key_type (boost::property_traits<PMap>::key_type) informs the library what type of object the property belongs to:

    • graph_traits<G>::vertex_descriptor attaches the attribute to objects of node type (vertices)
    • graph_traits<G>::edge_descriptor attaches attributes to the edges
    • G* attaches attributes at the graph level

    Therefore you need to use vertex_descriptor instead of VertexP* for these maps:

    dp.property("fixedsize", boost::make_constant_property<Graph::vertex_descriptor>(+"true"));
    dp.property("width",     boost::make_constant_property<Graph::vertex_descriptor>(1));
    dp.property("height",    boost::make_constant_property<Graph::vertex_descriptor>(1));
    

    Note that default streaming operations are used so there is no need to specifically convert to std::string

    Note though that the attributes are being written to temporary streams, so std::boolalpha is not honored. Also note that using a string literal would lead to the propertymap instantiating with char const(&)[5], which is why +"true" is used (decaying to char const*).

    Full Demo

    Live On Coliru

    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/graphviz.hpp>
    
    struct VertexP {
        std::string tag, shape, style, pos;
    };
    
    struct ArrowP {
        std::string symbol, color, style;
    };
    
    using Graph = boost::adjacency_list<
        boost::vecS, boost::vecS, boost::directedS,
        VertexP, ArrowP>;
    
    int main() {
        Graph g;
    
        boost::dynamic_properties dp;
        dp.property("rankdir", boost::make_constant_property<Graph*>(+"TB"));
        dp.property("node_id", get(&VertexP::tag,   g));
        dp.property("label",   get(&VertexP::tag,   g));
        dp.property("shape",   get(&VertexP::shape, g));
        dp.property("style",   get(&VertexP::style, g));
        dp.property("pos",     get(&VertexP::pos,   g));
        dp.property("label",   get(&ArrowP::symbol, g));
        dp.property("color",   get(&ArrowP::color,  g));
        dp.property("style",   get(&ArrowP::style,  g));
    
        dp.property("fixedsize", boost::make_constant_property<Graph::vertex_descriptor>(+"true"));
        dp.property("width",     boost::make_constant_property<Graph::vertex_descriptor>(1));
        dp.property("height",    boost::make_constant_property<Graph::vertex_descriptor>(1));
    
        add_edge(
                add_vertex({"foo", "diamond", "dotted", "0,1"}, g),
                add_vertex({"bar", "circle", "dashed", "1,1"}, g),
                {"foo-bar", "blue", "dashed"},
                g);
    
        write_graphviz_dp(std::cout, g, dp);
    }
    

    Prints

    digraph G {
    rankdir=TB;
    bar [fixedsize=true, height=1, label=bar, pos="1,1", shape=circle, style=dashed, width=1];
    foo [fixedsize=true, height=1, label=foo, pos="0,1", shape=diamond, style=dotted, width=1];
    foo->bar  [color=blue, label="foo-bar", style=dashed];
    }