4
$\begingroup$

Say I have an expression {1,{{2,3},4}}. It's TreeForm looks as follows:

{1,{{2,3},4}} //TreeForm

enter image description here

Now, on each level of that tree I would like to draw an edge where there isn't one, i.e. between 1 and List (first level), between List and 4 (second level) and between 2 and 3 (third level). Is it possible to do it in an efficient way? Can I somehow control the direction of all of these edges (including already existing ones)? I tried to use IGExpressionTree from the IGraph package together with EdgeAdd but it didn't work. Any suggestions?

$\endgroup$
  • 1
    $\begingroup$ maybe EdgeAdd[GraphComputation`ExpressionGraph[{1, {{2, 3}, 4}} ], {2->3,4->7,5->6}]? $\endgroup$ – kglr May 23 at 11:50
  • $\begingroup$ @kglr Thanks! Does that work, I've tried EdgeAdd[IGExpressionTree[{1, {{2, 3}, 4}}, VertexLabels->"Subexpression"],4\[UndirectedEdge]6], but that didn't work, I wonder why.. $\endgroup$ – amator2357 May 23 at 11:55
  • 1
    $\begingroup$ What if you have more than two nodes at the same level in the tree? $\endgroup$ – Szabolcs May 23 at 12:02
  • 1
    $\begingroup$ @amator2357 IGExpressionTree does not use the same vertex names as GraphComputation`ExpressionGraph $\endgroup$ – Szabolcs May 23 at 12:07
  • $\begingroup$ @Szabolcs it'll never happen for my case $\endgroup$ – amator2357 May 23 at 12:07
4
$\begingroup$
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

$\endgroup$
5
$\begingroup$

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.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.