Can I get boost :: write_graphviz to only write edges?
I am trying to get BGL to output a file that only has edges, since I am making the maximum connected component and I do not want to erase the vertices, but I also do not want to draw them if there is no edge.
My dot file right now:
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 make_edge_writer(w_map)
ensures that I print the weight (ignore the negative signs, I am actually making the maximum spanning tree, but my toy example had positive edges).
Now graphviz draws 9 vertices in my regular graph, plus the vertices {10, 11, 12) individually. If I manually edit my points file like this:
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 redundant vertices! Which basically means that Graphviz doesn't have to know the vertices in advance, right?
So, does anyone know how I can get write_graphviz
to not write the vertex indices in advance? I don't want to delete these vertices because in real life examples the redundant vertices might be inside the graph and my vertex numbers don't match my input.
Also, it really doesn't really matter, but it bullied me and I was wondering if anyone knows how to do this. I tried to move from boost::default_writer()
to my own code (which did nothing), but that didn't seem to make any difference.
source to share
Three parts answer
- Predefining vertices in Graphviz can be helpful
Do you want to filter nodes
- You can customize
PropertyWriter
- You can customize the rendering of the graph
I would suggest the former (because of "express your intent") or the latter (because of the "separation of concerns").
Predefining vertices in Graphviz can be helpful
Graphviz does not need to know the vertices in advance if they do not need some attributes other than the default.
0 [label="Node 0"];
1 [shape="Mrect"];
0 -- 1; // works
But
0 [label="Node 0"] -- 1 [shape="Mrect"]; // doesn't work
Actually
0 [label="Node 0"];
0 -- 1 [label="oops"]; // oops
Sets the "oops" label at the border, not the vertex with ID 1.
Connect PropertyWriter
What you really want to do is filter out vertices with zero adjacent vertices, I would say. If you insist not to do this, you can pass custom PropertyWriter properties to the EdgePropertyWriter. I guess this might 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_;
};
Renderer setup
You can use gvpr
to post-process the output:
gvpr -c 'N[$.degree==0]{$.style="invis"}' test.dot | dot -Tpng > test.png
Or, to really remove the use of space:
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 the documentation might fix this): gvpr
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
source to share