Reputation: 1608
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
Reputation: 392903
Three part answer
You want to filter out the nodes
PropertyWriter
I'd suggest the first (because of "express your intent") or the latter (because of "separation of concerns").
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.
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_;
};
You can use gvpr
to postprocess the output:
gvpr -c 'N[$.degree==0]{$.style="invis"}' test.dot | dot -Tpng > test.png
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
Upvotes: 5