25
$\begingroup$

Ok, so the goal is to visualize the execution of this expression

foo /@ {3 + 1, bar /@ {1 + 2, {4 + 7}}}

in the following fashion using nested rectangles with mouseover highlighting and tooltips that show the highlighted subexpression's values.

enter image description here

Ok, that works and looks great, but the code is ugly:

Clear[foo, bar];
expr = MapAll[h1, 
   Unevaluated[foo /@ {3 + 1, bar /@ {1 + 2, {4 + 7}}}], 
   Heads -> True];

expr = expr //. h1[x_] :> h2[HoldForm[x], h3[x]];

expr = expr //. 
   h2[x_, y_] :> 
    Mouseover[
     Tooltip[Framed[x, Background -> White, FrameMargins -> 10, 
       RoundingRadius -> 10], y], 
     Tooltip[Framed[x, Background -> Hue[0.6, 1, 1, 0.1], 
       FrameMargins -> 10, RoundingRadius -> 10], y]];

Cleanh2[x___] := 
 Module[{xx = {x}}, 
  xx = xx //. {Framed[a_] :> a, Tooltip[b_, c_] :> c, 
     Verbatim[HoldForm][d__] :> d, Mouseover[e_, f_] :> e};
  Sequence @@ xx]

expr = expr //. h3 -> Cleanh2;

MouseAppearance[
 Magnify[Dynamic[Evaluate[expr] //. Verbatim[HoldForm][d___] :> d], 
  1], "+"]

and quickly breaks:

expr = MapAll[h1, 
   Unevaluated[
    Module[{t = RandomInteger[1, 10]}, 
     MapThread[f, {t, RotateLeft[t] + RotateRight[t]}]]], 
   Heads -> True];

expr = expr //. h1[x_] :> h2[HoldForm[x], h3[x]];

expr = expr //. 
   h2[x_, y_] :> 
    Mouseover[
     Tooltip[Framed[x, Background -> White, FrameMargins -> 10, 
       RoundingRadius -> 10], y], 
     Tooltip[Framed[x, Background -> Hue[0.6, 1, 1, 0.1], 
       FrameMargins -> 10, RoundingRadius -> 10], y]];

expr = expr //. h3 -> Cleanh2;
MouseAppearance[
 Magnify[Dynamic[Evaluate[expr] //. Verbatim[HoldForm][d___] :> d], 
  1], "+"]

How can I do this cleanly in a general fashion? There must be a way...

$\endgroup$
15
  • 4
    $\begingroup$ Strongly related: "The clearest way to represent Mathematica's evaluation sequence." $\endgroup$ Commented Jun 8, 2012 at 8:53
  • 2
    $\begingroup$ You don't really visualize evaluation, it seems - just a structure of your unevaluated expression. You may want to check this out. $\endgroup$ Commented Jun 8, 2012 at 8:53
  • $\begingroup$ This question was inspired by Bret Victor's approach (vimeo.com/36579366) to debugging code visually. $\endgroup$
    – M.R.
    Commented Jun 8, 2012 at 8:56
  • 7
    $\begingroup$ The general problem with this approach is that it will mess up scoping and generally the evaluation process, because you can not take pieces of code, evaluate them separately, and expect that this would correspond to the original evaluation, unless your code is completely referentially transparent and free of side effects. The approach based on Trace works because nothing is evaluated there, and the output of Trace reflects the actual evaluation process. Other approach would be one of traditional debuggers. But for that, you need execution context. Probably doable, but lots of work. $\endgroup$ Commented Jun 8, 2012 at 9:19
  • 1
    $\begingroup$ On a philosophical note, the tool you want is fancy but hardly practical, at least to me. What I value in debugging tools is that they are selective, so that they show only parts I want to look at, and help me quickly filter out the rest. So, to me, a good debugger is a good filter in the first place, allowing me to skip the stuff I don't really want to see. So, at least in the form you want it currently, your tool will be wasteful (both for computer and for you, because you will have to go through all these fancy tooltips to find the place you want), and IMO for no good reason. $\endgroup$ Commented Jun 8, 2012 at 9:26

1 Answer 1

2
$\begingroup$

You could use a combination of ExpressionTree and TreeFold.

ExpressionTree[Unevaluated[foo /@ {3 + 1, bar /@ {1 + 2, {4 + 7}}}]]

ExpressionTree has some nice options, so this might be useful:

ExpressionTree[Unevaluated[foo /@ {3 + 1, bar /@ {1 + 2, {4 + 7}}}], "Arguments"]

But then, if you use the example from the documenation of TreeForm, you can do this, which is close to the form in the original post:

TreeFold[
  {Framed[Row[{#, Row[#2, " "]}]] &, Framed}, 
  ExpressionTree[Unevaluated[foo /@ {3 + 1, bar /@ {1 + 2, {4 + 7}}}]]]
$\endgroup$
2
  • $\begingroup$ Can you make this interactive? $\endgroup$
    – M.R.
    Commented Apr 11, 2022 at 17:26
  • $\begingroup$ What part of it do you want to make interactive? You might be interested in TraceDialog, which interactively steps through evaluation of an expression. Or TracePrint that will just print out each step. If you want the tooltips, I assume it would work to add Tooltip at the desired places in the functions passed to TreeFold, but I haven't tried it. $\endgroup$
    – lericr
    Commented Apr 11, 2022 at 19:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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