adinutzyc21
adinutzyc21

Reputation: 1608

Can I get boost::write_graphviz to write only the edges?

I am trying to get BGL to output a file that only has the edges, since I am doing a maximum connected component and I don't want to erase vertices but I also don't want to draw them if there's no edge.

My dot file right now is:

graph G {
0;
1;
2;
3;
4;
5;
6;
7;
8;
9;
10;
11;
12;
0--1 [label="-3"];
0--5 [label="-2"];
2--3 [label="-8"];
3--8 [label="-4"];
4--5 [label="-1"];
4--6 [label="-6"];
4--7 [label="-5"];
4--8 [label="-10"];
8--9 [label="-9"];
}

and I print it by running

boost::write_graphviz(myfile, G, boost::default_writer(), make_edge_writer(w_map));

where the make_edge_writer(w_map) ensures I get the weight printed out (ignore the negative signs, I'm actually doing a maximum spanning tree but my toy example had positive edges).

Now, graphviz draws the 9 vertices in my correct graph, plus vertices {10, 11, 12) individually. If I manually edit my dot file to be:

graph G {
0--1 [label="-3"];
0--5 [label="-2"];
2--3 [label="-8"];
3--8 [label="-4"];
4--5 [label="-1"];
4--6 [label="-6"];
4--7 [label="-5"];
4--8 [label="-10"];
8--9 [label="-9"];
}

and then run graphviz, I get the same graph minus the surplus vertices! Which basically means graphviz doesn't need to know the vertices beforehand, right?

So, anyone know how I can get write_graphviz to not write the vertex indices beforehand? I don't want to remove those vertices because in real examples the surplus vertices could be inside the graph and then my vertex numbers wouldn't correspond to my input..

Also, this is really not a big deal, but it's been bugging me and I was wondering if anyone knew how to do it. I tried changing from boost::default_writer() to my own code (that didn't do anything), but it didn't seem to make any difference.

Upvotes: 3

Views: 939

Answers (1)

sehe
sehe

Reputation: 392903

Three part answer

  • Predefining vertices in Graphviz can be useful

You want to filter out the nodes

  • You can tweak the PropertyWriter
  • You can tweak the graph renderer

I'd suggest the first (because of "express your intent") or the latter (because of "separation of concerns").

Predefining vertices in Graphviz can be useful

Graphviz doesn't need to know the vertices beforehand, unless they require some non-default attributes.

 0 [label="Node 0"];
 1 [shape="Mrect"];

 0 -- 1; // works

But

 0 [label="Node 0"] -- 1 [shape="Mrect"]; // doesn't work

In fact

 0 [label="Node 0"];
 0 -- 1 [label="oops"]; // oops

Sets the "oops" label on the edge, not the vertex with id 1.


Tweak the PropertyWriter

What you really want to do is filter out vertices having zero adjacent vertices, I'd say. If you insist on not doing this, you can pass in custom PropertyWriter implementations for the EdgePropertyWriter. I assume this could work for you

  template <class Name>
  class my_vertex_writer {
  public:
    my_vertex_writer(Graph& g) : g_(g) {}

    template <class Vertex>
    void operator()(std::ostream& out, const Vertex& v) const {
         // pseudo-code!
         if (0 == boost::size(in_edges(v, g_)))
            out << "[style=\"invis\"]";
    }
  private:
    Graph& g_;
  };

Tweak the renderer

You can use gvpr to postprocess the output:

gvpr -c 'N[$.degree==0]{$.style="invis"}' test.dot | dot -Tpng > test.png

enter image description here

Or, to really remove the space usage as well:

gvpr -c 'N[$.degree==0]{delete(0,$);}' test.dot | dot -Tpng > test.png

For some reason, I seemed to need to repeat this (I'm sure a trip to gvpr documentation could fix this):

cat test.dot | 
    gvpr -c 'N[$.degree==0]{delete(0,$)}' |
    gvpr -c 'N[$.degree==0]{delete(0,$)}' |
    gvpr -c 'N[$.degree==0]{delete(0,$)}' |
    dot -Tpng > test.png

enter image description here

Upvotes: 5

Related Questions