Update 10/27: I've put detailed steps for achieving consistent scale in an answer. Basically for each Graphics object you need to fix all padding/margins to 0 and manually specify plotRange and imageSize that such that 1) plotRange includes all graphics 2) imageSize=scale*plotRange
Still now sure how to do 1) in full generality, a solution that works for Graphics consisting of points and thick lines (AbsoluteThickness) is given
I'm using "Inset" in VertexRenderingFunction and "VertexCoordinates" to guarantee consistent appearance among subgraphs of a graph. Those subgraphs are drawn as vertices of another graph, using "Inset". There are two problems, one is that resulting boxes are not cropped around the graph (ie, graph with one vertex still gets placed in a big box), and another is that there's strange variation among sizes (you can see one box is vertical). Can anyone see a way around these problems?
This is related to an earlier question of how to keep vertex sizes looking the same, and while Michael Pilat's suggestion of using Inset works to keep vertices rendering at the same scale, overall scale may be different. For instance on the left branch, the graph consisting of vertices 2,3 is stretched relative to the "2,3" subgraph in the top graph, even though I'm using absolute vertex positioning for both
(source: yaroslavvb.com)
(*utilities*)intersect[a_, b_] := Select[a, MemberQ[b, #] &];
induced[s_] := Select[edges, #~intersect~s == # &];
Needs["GraphUtilities`"];
subgraphs[
verts_] := (gr =
Rule @@@ Select[edges, (Intersection[#, verts] == #) &];
Sort /@ WeakComponents[gr~Join~(# -> # & /@ verts)]);
(*graph*)
gname = {"Grid", {3, 3}};
edges = GraphData[gname, "EdgeIndices"];
nodes = Union[Flatten[edges]];
AppendTo[edges, #] & /@ ({#, #} & /@ nodes);
vcoords = Thread[nodes -> GraphData[gname, "VertexCoordinates"]];
(*decompose*)
edgesOuter = {};
pr[_, _, {}] := None;
pr[root_, elim_,
remain_] := (If[root != {}, AppendTo[edgesOuter, root -> remain]];
pr[remain, intersect[Rest[elim], #], #] & /@
subgraphs[Complement[remain, {First[elim]}]];);
pr[{}, {4, 5, 6, 1, 8, 2, 3, 7, 9}, nodes];
(*visualize*)
vrfInner =
Inset[Graphics[{White, EdgeForm[Black], Disk[{0, 0}, .05], Black,
Text[#2, {0, 0}]}, ImageSize -> 15], #] &;
vrfOuter =
Inset[GraphPlot[Rule @@@ induced[#2],
VertexRenderingFunction -> vrfInner,
VertexCoordinateRules -> vcoords, SelfLoopStyle -> None,
Frame -> True, ImageSize -> 100], #] &;
TreePlot[edgesOuter, Automatic, nodes,
EdgeRenderingFunction -> ({Red, Arrow[#1, 0.2]} &),
VertexRenderingFunction -> vrfOuter, ImageSize -> 500]
Here's another example, same problem as before, but the difference in relative scales is more visible. The goal is to have parts in the second picture match precisely the parts in the first picture.
(source: yaroslavvb.com)
(* Visualize tree decomposition of a 3x3 grid *)
inducedGraph[set_] := Select[edges, # \[Subset] set &];
Subset[a_, b_] := (a \[Intersection] b == a);
graphName = {"Grid", {3, 3}};
edges = GraphData[graphName, "EdgeIndices"];
vars = Range[GraphData[graphName, "VertexCount"]];
vcoords = Thread[vars -> GraphData[graphName, "VertexCoordinates"]];
plotHighlight[verts_, color_] := Module[{vpos, coords},
vpos =
Position[Range[GraphData[graphName, "VertexCount"]],
Alternatives @@ verts];
coords = Extract[GraphData[graphName, "VertexCoordinates"], vpos];
If[coords != {}, AppendTo[coords, First[coords] + .002]];
Graphics[{color, CapForm["Round"], JoinForm["Round"],
Thickness[.2], Opacity[.3], Line[coords]}]];
jedges = {{{1, 2, 4}, {2, 4, 5, 6}}, {{2, 3, 6}, {2, 4, 5, 6}}, {{4,
5, 6}, {2, 4, 5, 6}}, {{4, 5, 6}, {4, 5, 6, 8}}, {{4, 7, 8}, {4,
5, 6, 8}}, {{6, 8, 9}, {4, 5, 6, 8}}};
jnodes = Union[Flatten[jedges, 1]];
SeedRandom[1]; colors =
RandomChoice[ColorData["WebSafe", "ColorList"], Length[jnodes]];
bags = MapIndexed[plotHighlight[#, bc[#] = colors[[First[#2]]]] &,
jnodes];
Show[bags~
Join~{GraphPlot[Rule @@@ edges, VertexCoordinateRules -> vcoords,
VertexLabeling -> True]}, ImageSize -> Small]
bagCentroid[bag_] := Mean[bag /. vcoords];
findExtremeBag[vec_] := (
vertList = First /@ vcoords;
coordList = Last /@ vcoords;
extremePos =
First[Ordering[jnodes, 1,
bagCentroid[#1].vec > bagCentroid[#2].vec &]];
jnodes[[extremePos]]
);
extremeDirs = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
extremeBags = findExtremeBag /@ extremeDirs;
extremePoses = bagCentroid /@ extremeBags;
vrfOuter =
Inset[Show[plotHighlight[#2, bc[#2]],
GraphPlot[Rule @@@ inducedGraph[#2],
VertexCoordinateRules -> vcoords, SelfLoopStyle -> None,
VertexLabeling -> True], ImageSize -> 100], #] &;
GraphPlot[Rule @@@ jedges, VertexRenderingFunction -> vrfOuter,
EdgeRenderingFunction -> ({Red, Arrowheads[0], Arrow[#1, 0]} &),
ImageSize -> 500,
VertexCoordinateRules -> Thread[Thread[extremeBags -> extremePoses]]]
Any other suggestions for aesthetically pleasing visualization of graph operations are welcome.