Adding edges to a TreeForm of an expression
With IGraph/M,
g = IGExpressionTree[{1, {{2, 3}, 4}}]
Notice that the vertices created by this function are lists (encoding subexpression positions), and their length is the same if they are on the same tree level.
IGExpressionTree[{1, {{2, 3}, 4}}, VertexLabels -> "Name"]
Thus we can easily create the additional edges:
pathEdges[list_] := DirectedEdge @@@ Partition[list, 2, 1]
newEdges = Flatten[pathEdges /@ GatherBy[VertexList[g], Length]]
(* {{1} \[DirectedEdge] {2}, {2, 1, 1} \[DirectedEdge] {2, 1, 2}, {2, 1} \[DirectedEdge] {2, 2}} *)
EdgeAdd[g, newEdges]
If you never have more than two nodes at a level, then simply use
EdgeAdd[
g,
DirectedEdge @@@ GatherBy[Most@VertexList[g], Length]
]
Both of these rely on the order in which vertices are returned by IGExpressionTree
(which is sorted) as well as on GatherBy
not changing this order.
g0 = GraphComputation`ExpressionGraph[{1, {{2, 3}, 4}} , ImageSize -> 200];
newedges = UndirectedEdge @@@ GatherBy[Rest@VertexList@g0, GraphDistance[g0, 1, #] &]
{2 \[UndirectedEdge] 3, 4 \[UndirectedEdge] 7, 5 \[UndirectedEdge] 6}
g1 = EdgeAdd[g0, newedges];
Row[{g0, g1}, Spacer[10]]
Alternatively, you can use newedges
to post-process the TreeForm
of the input expression to add the new lines:
tf1 = TreeForm[{1, {{2, 3}, 4}}, DirectedEdges -> True, ImageSize -> Medium];
tf2 = RawBoxes[ToBoxes[tf1] /. l : (_ArrowBox | _LineBox) :>
{l, Dashing @ Small, LineBox @ # }] &[List @@@ newedges];
Row @ {tf1, tf2}
If there are more than two nodes at the same level in the tree:
g0 = GraphComputation`ExpressionGraph[{1, {{2, 3}, 4, 5}} , ImageSize -> 200];
newedges = Join @@ Map[UndirectedEdge @@@ # &,
Subsets[#, {2}] & /@ GatherBy[Rest@VertexList@g0, GraphDistance[g0, 1, #] &]]
{2 \[UndirectedEdge] 3, 4 \[UndirectedEdge] 7, 4 \[UndirectedEdge] 8, 7 \[UndirectedEdge] 8, 5 \[UndirectedEdge] 6}
g1 = SetProperty[EdgeAdd[g0, newedges],
{EdgeShapeFunction -> {Alternatives @@ newedges :> "CurvedArc"}}]
Row[{g0, g1}, Spacer[10]]