Adding edges to a TreeForm of an expression

With IGraph/M,

g = IGExpressionTree[{1, {{2, 3}, 4}}]

enter image description here

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"]

enter image description here

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]

enter image description here

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]]

enter image description here

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}

enter image description here

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]]

enter image description here