Function Repository Resource:

AnnotatedExpression

Source Notebook

Represent an expression in an unevaluated form with a callout annotation

Contributed by: Edmund B Robinson

ResourceFunction["AnnotatedExpression"][expr,annotation]

displays expr annotated with annotation below expr.

ResourceFunction["AnnotatedExpression"][expr,annotation,pos]

displays expr with annotation in the position specified by pos.

Details and Options

The result of ResourceFunction["AnnotatedExpression"] is an unevaluated representation of expr with head Interpretation.
The result can be evaluated in place. See Evaluate in Place.
The result is not evaluated until supplied as input.
The annotation can be any expression.
Supported positions include Above and Below.
ResourceFunction["AnnotatedExpression"] takes the following options:
CalloutStyleDirective[LightGray,Thin]style used for strokes of the callout
ImageSizeAutomaticthe overall image size of the annotation expression displayed in the callout
ImageSizeAction"ShrinkToFit"action to take if the annotation size does not match the image size
ItemSize15width of the callout
LeaderSize1length to use for the callout leader
NeckSize1length to use for the callout neck
CalloutStyle does not support specifying a knockout style.
ResourceFunction["AnnotatedExpression"] has the attribute HoldFirst.

Examples

Basic Examples (3) 

Create a simple annotated expression:

In[1]:=
ResourceFunction["AnnotatedExpression"][1 + 1, "An addition"]
Out[1]=

Copy it and evaluate:

In[2]:=
1 + 1
Out[2]=

AnnotatedExpression returns an annotated version of the input without evaluating it:

In[3]:=
ResourceFunction["AnnotatedExpression"][
 RandomVariate[NormalDistribution[], 10],
 "10 Standard Normal Variates",
 ItemSize -> 22]
Out[3]=

Copying the output expression to an input cell results in each evaluation producing a new set of pseudo random numbers:

In[4]:=
RandomVariate[
NormalDistribution[], 10]
Out[4]=

The annotation can be placed Above or Below the expression:

In[5]:=
ResourceFunction["AnnotatedExpression"][Entity["Country", "Bermuda"], Framed[Entity["Country", "Bermuda"]["Flag"]], Above]
Out[5]=
In[6]:=
ResourceFunction["AnnotatedExpression"][Entity["Country", "Bermuda"], Framed[Entity["Country", "Bermuda"]["Flag"]], Below]
Out[6]=

Copy the previous result and use it like the Entity it represents:

In[7]:=
(* Evaluate this cell to get the example input *) CloudGet["https://www.wolframcloud.com/obj/28e82c20-aa71-482b-8ff2-a8369252baae"]
Out[7]=

Scope (3) 

Annotate an expression with information about itself:

In[8]:=
ResourceFunction["AnnotatedExpression"][
 CellularAutomaton[30, {{1}, 0}, 20],
 RulePlot@CellularAutomaton[30],
 ItemSize -> 20,
 ImageSize -> Medium]
Out[8]=
In[9]:=
ArrayPlot[ 
CellularAutomaton[30, {{1}, 0}, 20] ]
Out[9]=

Annotate with a visual summary of the expression:

In[10]:=
ResourceFunction["AnnotatedExpression"][
 RandomVariate[PoissonDistribution[7], 200],
 DiscretePlot[
  PDF[PoissonDistribution[7], x], {x, 0, 20},
  Filling -> Axis,
  Axes -> {True, False}
  ],
 ItemSize -> 25,
 ImageSize -> Small]
Out[10]=
In[11]:=
Histogram[ 
RandomVariate[
PoissonDistribution[7], 200] ]
Out[11]=

Annotate with a visualization of the expression:

In[12]:=
{
 ResourceFunction["AnnotatedExpression"][GaussianMatrix[3], MatrixPlot[GaussianMatrix[3], Frame -> False], ItemSize -> 10],
 ResourceFunction["AnnotatedExpression"][HankelMatrix[7], MatrixPlot[HankelMatrix[7], Frame -> False], ItemSize -> 10]
 }
Out[12]=
In[13]:=
MatrixPlot@Dot[GaussianMatrix[3] , HankelMatrix[7]]
Out[13]=

Options (7) 

CalloutStyle (2) 

Supply a graphics directive:

In[14]:=
ResourceFunction["AnnotatedExpression"][
 Cone[],
 Graphics3D[Cone[], Boxed -> False],
 ItemSize -> 5,
 CalloutStyle -> Orange
 ]
Out[14]=

Combine multiple graphics directives with Directive:

In[15]:=
ResourceFunction["AnnotatedExpression"][
 Cone[],
 Graphics3D[Cone[], Boxed -> False],
 ItemSize -> 5,
 CalloutStyle -> Directive[Orange, Thick, Dashed]
 ]
Out[15]=

ImageSize (1) 

Specify the image size of the annotation:

In[16]:=
ResourceFunction["AnnotatedExpression"][Sin[\[FormalX]], Plot[Sin[\[FormalX]], {\[FormalX], 0, 2 \[Pi]}], ImageSize -> #] & /@ {Tiny, Small, Medium}
Out[16]=

ImageSizeAction (1) 

See ImageSizeAction for a description of the settings:

In[17]:=
ResourceFunction["AnnotatedExpression"][
   ToeplitzMatrix[6],
   MatrixPlot[ToeplitzMatrix[6], Frame -> False, ImageSize -> 180], ItemSize -> 10,
   ImageSizeAction -> #] & /@ {"Clip", "ResizeToFit", "Scrollable", "ShrinkToFit"}
Out[17]=

ItemSize (1) 

Use ItemSize to set the width of the annotated expression:

In[18]:=
ResourceFunction["AnnotatedExpression"][
   Range[2, 12, 2],
   NumberLinePlot[Range[2, 12, 2]],
   ImageSize -> Medium,
   ItemSize -> #
   ] & /@ Range[15, 25, 5]
Out[18]=

LeaderSize (1) 

Use LeaderSize to set the leader height of the annotation callout:

In[19]:=
ResourceFunction["AnnotatedExpression"][
   ExampleData[{"Statistics", "AirlinePassengerMiles"}],
   BoxWhiskerChart[
    ExampleData[{"Statistics", "AirlinePassengerMiles"}], Sequence[
    BarOrigin -> Left, PlotTheme -> "Wide", Frame -> False]],
   ItemSize -> 28, ImageSize -> Medium, LeaderSize -> #] & /@ {1, 5}
Out[19]=

NeckSize (1) 

Use the "NeckSize" option to set the neck height of the annotation callout:

In[20]:=
ResourceFunction["AnnotatedExpression"][
   ExampleData[{"Statistics", "AirlinePassengerMiles"}],
   BoxWhiskerChart[
    ExampleData[{"Statistics", "AirlinePassengerMiles"}], Sequence[
    BarOrigin -> Left, PlotTheme -> "Wide", Frame -> False]],
   ItemSize -> 28, ImageSize -> Medium, "NeckSize" -> #] & /@ {1, 5}
Out[20]=

Possible Issues (3) 

Several warning messages are generated when using a dynamic expression containing InputField:

In[21]:=
DynamicSetting@
 DynamicModule[{r = 5},
  ResourceFunction["AnnotatedExpression"][
   Range[InputField[Dynamic@r, Number, FieldSize -> 2]],
   Dynamic@NumberLinePlot[Range[r]],
   ItemSize -> 8
   ]]
Out[21]=

The messages are issued when the expression is evaluated:

In[22]:=
Total[ \!\(\*
TagBox[
DynamicModuleBox[{$CellContext`r$$ = 10}, 
InterpretationBox[
TagBox[GridBox[{
{
TagBox[
RowBox[{"Range", "[", 
InputFieldBox[Dynamic[$CellContext`r$$], Number,
FieldSize->2], "]"}],
HoldForm], "\[SpanFromLeft]"},
{
ItemBox["\<\"\"\>",
Frame->{{
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}, {
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}},
StripOnInput->False], 
ItemBox["\<\"\"\>",
Frame->{{None, 
Directive[
GrayLevel[0.85], 
Thickness[Tiny]]}, {
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}},
StripOnInput->False]},
{
ItemBox["\<\"\"\>",
Frame->{{None, 
Directive[
GrayLevel[0.85], 
Thickness[Tiny]]}, Automatic},
StripOnInput->False], 
ItemBox["\<\"\"\>",
Frame->{{
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}, Automatic},
StripOnInput->False]},
{
StyleBox[
PaneBox[
DynamicBox[ToBoxes[
NumberLinePlot[
Range[$CellContext`r$$]], StandardForm],
ImageSizeCache->{100., {8., 13.272562926242308`}}],
Alignment->Center,
ImageSize->Small,
ImageSizeAction->"ShrinkToFit"], "Output",
StripOnInput->False], "\[SpanFromLeft]"}
},
AutoDelete->False,
BaseStyle->"Output",
BaselinePosition->1,
GridBoxAlignment->{"Columns" -> {{Center}}},
GridBoxItemSize->{"Columns" -> {{4}}, "Rows" -> {Automatic}, "RowsIndexed" -> {2 -> 1, 3 -> 1}},
GridBoxSpacings->{"Columns" -> {{0}}, "Rows" -> {{0}}}],
"Grid"],
Range[
InputField[
Dynamic[$CellContext`r$$], Number, FieldSize -> 2]]],
DynamicModuleValues:>{}],
Setting]\) ]
Out[22]=

Use Quiet to suppress these messages:

In[23]:=
Quiet@Total[ \!\(\*
TagBox[
DynamicModuleBox[{$CellContext`r$$ = 10}, 
InterpretationBox[
TagBox[GridBox[{
{
TagBox[
RowBox[{"Range", "[", 
InputFieldBox[Dynamic[$CellContext`r$$], Number,
FieldSize->2], "]"}],
HoldForm], "\[SpanFromLeft]"},
{
ItemBox["\<\"\"\>",
Frame->{{
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}, {
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}},
StripOnInput->False], 
ItemBox["\<\"\"\>",
Frame->{{None, 
Directive[
GrayLevel[0.85], 
Thickness[Tiny]]}, {
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}},
StripOnInput->False]},
{
ItemBox["\<\"\"\>",
Frame->{{None, 
Directive[
GrayLevel[0.85], 
Thickness[Tiny]]}, Automatic},
StripOnInput->False], 
ItemBox["\<\"\"\>",
Frame->{{
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}, Automatic},
StripOnInput->False]},
{
StyleBox[
PaneBox[
DynamicBox[ToBoxes[
NumberLinePlot[
Range[$CellContext`r$$]], StandardForm],
ImageSizeCache->{100., {8., 13.272562926242308`}}],
Alignment->Center,
ImageSize->Small,
ImageSizeAction->"ShrinkToFit"], "Output",
StripOnInput->False], "\[SpanFromLeft]"}
},
AutoDelete->False,
BaseStyle->"Output",
BaselinePosition->1,
GridBoxAlignment->{"Columns" -> {{Center}}},
GridBoxItemSize->{"Columns" -> {{4}}, "Rows" -> {Automatic}, "RowsIndexed" -> {2 -> 1, 3 -> 1}},
GridBoxSpacings->{"Columns" -> {{0}}, "Rows" -> {{0}}}],
"Grid"],
Range[
InputField[
Dynamic[$CellContext`r$$], Number, FieldSize -> 2]]],
DynamicModuleValues:>{}],
Setting]\) ]
Out[23]=

Neat Examples (2) 

Create a dynamic annotation to view the RulePlot of CellularAutomaton inline before evaluating the simulation:

In[24]:=
DynamicSetting@
 DynamicModule[{r = 30},
  ResourceFunction["AnnotatedExpression"][
   CellularAutomaton[
    InputField[Dynamic@r, Number, FieldSize -> 2], {{1}, 0}, 16],
   Dynamic[RulePlot@CellularAutomaton[r]], Sequence[
   ItemSize -> 22, ImageSize -> Medium]]
  ]
Out[24]=

Update the rule and press the key to update the RulePlot annotation before plotting:

In[25]:=
Quiet@ArrayPlot[ \!\(\*
TagBox[
DynamicModuleBox[{$CellContext`r$$ = 99}, 
InterpretationBox[
TagBox[GridBox[{
{
TagBox[
RowBox[{"CellularAutomaton", "[", 
RowBox[{
InputFieldBox[Dynamic[$CellContext`r$$], Number,
FieldSize->2], ",", 
RowBox[{"{", 
RowBox[{
RowBox[{"{", "1", "}"}], ",", "0"}], "}"}], ",", "16"}], "]"}],
HoldForm], "\[SpanFromLeft]"},
{
ItemBox["\<\"\"\>",
Frame->{{
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}, {
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}},
StripOnInput->False], 
ItemBox["\<\"\"\>",
Frame->{{None, 
Directive[
GrayLevel[0.85], 
Thickness[Tiny]]}, {
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}},
StripOnInput->False]},
{
ItemBox["\<\"\"\>",
Frame->{{None, 
Directive[
GrayLevel[0.85], 
Thickness[Tiny]]}, Automatic},
StripOnInput->False], 
ItemBox["\<\"\"\>",
Frame->{{
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}, Automatic},
StripOnInput->False]},
{
StyleBox[
PaneBox[
DynamicBox[ToBoxes[
RulePlot[
CellularAutomaton[$CellContext`r$$]], StandardForm],
ImageSizeCache->{200., {11., 16.18}}],
Alignment->Center,
ImageSize->Medium,
ImageSizeAction->"ShrinkToFit"], "Output",
StripOnInput->False], "\[SpanFromLeft]"}
},
AutoDelete->False,
BaseStyle->"Output",
BaselinePosition->1,
GridBoxAlignment->{"Columns" -> {{Center}}},
GridBoxItemSize->{"Columns" -> {{11}}, "Rows" -> {Automatic}, "RowsIndexed" -> {2 -> 1, 3 -> 1}},
GridBoxSpacings->{"Columns" -> {{0}}, "Rows" -> {{0}}}],
"Grid"],
CellularAutomaton[
InputField[
Dynamic[$CellContext`r$$], Number, FieldSize -> 2], {{1}, 0}, 16]],
DynamicModuleValues:>{}],
Setting]\) ]
Out[25]=

Create dynamic annotations to view graphics primitives inline before evaluating the plot:

In[26]:=
{
 DynamicSetting@
  DynamicModule[{shade = HalftoneShading[]},
   ResourceFunction["AnnotatedExpression"][
    PopupMenu[
     Dynamic[shade], {HalftoneShading[], StippleShading[], HatchShading[], GoochShading[]}],
    Dynamic[
     Graphics3D[{shade, InfinitePlane[{{1, 0, 0}, {1, 1, 1}, {0, 0, 1}}]}, Boxed -> False]],
    Above,
    ItemSize -> 10]
   ],
 DynamicSetting@
  DynamicModule[{shp = Cone[]},
   ResourceFunction["AnnotatedExpression"][
    PopupMenu[
     Dynamic[shp], {Cone[], Sphere[], Cuboid[], Octahedron[]}],
    Dynamic[Graphics3D[shp, Boxed -> False]],
    Above,
    ItemSize -> 10]
   ]
 }
Out[26]=
In[27]:=
Graphics3D[{\!\(\*
TagBox[
DynamicModuleBox[{$CellContext`shade$$ = HalftoneShading[0.5]}, 
InterpretationBox[
TagBox[GridBox[{
{
StyleBox[
PaneBox[
DynamicBox[ToBoxes[
Graphics3D[{$CellContext`shade$$, 
InfinitePlane[{{1, 0, 0}, {1, 1, 1}, {0, 0, 1}}]}, Boxed -> False], StandardForm],
ImageSizeCache->{100., {48., 52.}}],
Alignment->Center,
ImageSize->Small,
ImageSizeAction->"ShrinkToFit"], "Output",
StripOnInput->False], "\[SpanFromLeft]"},
{
ItemBox["\<\"\"\>",
Frame->{{None, 
Directive[
GrayLevel[0.85], 
Thickness[Tiny]]}, Automatic},
StripOnInput->False], 
ItemBox["\<\"\"\>",
Frame->{{
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}, Automatic},
StripOnInput->False]},
{
ItemBox["\<\"\"\>",
Frame->{{
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}, {None, 
Directive[
GrayLevel[0.85], 
Thickness[Tiny]]}},
StripOnInput->False], 
ItemBox["\<\"\"\>",
Frame->{{None, 
Directive[
GrayLevel[0.85], 
Thickness[Tiny]]}, {None, 
Directive[
GrayLevel[0.85], 
Thickness[Tiny]]}},
StripOnInput->False]},
{
TagBox[
PopupMenuBox[Dynamic[$CellContext`shade$$], {HalftoneShading[0.5]-> RowBox[{"HalftoneShading", "[", "]"}], StippleShading[
             0.5]->
RowBox[{"StippleShading", "[", "]"}], HatchShading[0.5]->
RowBox[{"HatchShading", "[", "]"}], GoochShading[{
LABColor[0.25, 0.4, -0.65], 
LABColor[0.55, 0.65, 0.65], 
LABColor[0.9, 0.05, 0.4]}]->
RowBox[{"GoochShading", "[", "]"}]}],
HoldForm], "\[SpanFromLeft]"}
},
AutoDelete->False,
BaseStyle->"Output",
BaselinePosition->4,
GridBoxAlignment->{"Columns" -> {{Center}}},
GridBoxItemSize->{"Columns" -> {{5}}, "Rows" -> {Automatic}, "RowsIndexed" -> {3 -> 1, 2 -> 1}},
GridBoxSpacings->{"Columns" -> {{0}}, "Rows" -> {{0}}}],
"Grid"],
PopupMenu[
Dynamic[$CellContext`shade$$], {
HalftoneShading[], 
StippleShading[], 
HatchShading[], 
GoochShading[]}]],
DynamicModuleValues:>{}],
Setting]\) , \!\(\*
TagBox[
DynamicModuleBox[{$CellContext`shp$$ = Cone[{{0, 0, -1}, {0, 0, 1}}]}, 
InterpretationBox[
TagBox[GridBox[{
{
StyleBox[
PaneBox[
DynamicBox[ToBoxes[
Graphics3D[$CellContext`shp$$, Boxed -> False], StandardForm],
ImageSizeCache->{100., {48., 52.}}],
Alignment->Center,
ImageSize->Small,
ImageSizeAction->"ShrinkToFit"], "Output",
StripOnInput->False], "\[SpanFromLeft]"},
{
ItemBox["\<\"\"\>",
Frame->{{None, 
Directive[
GrayLevel[0.85], 
Thickness[Tiny]]}, Automatic},
StripOnInput->False], 
ItemBox["\<\"\"\>",
Frame->{{
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}, Automatic},
StripOnInput->False]},
{
ItemBox["\<\"\"\>",
Frame->{{
Directive[
GrayLevel[0.85], 
Thickness[Tiny]], None}, {None, 
Directive[
GrayLevel[0.85], 
Thickness[Tiny]]}},
StripOnInput->False], 
ItemBox["\<\"\"\>",
Frame->{{None, 
Directive[
GrayLevel[0.85], 
Thickness[Tiny]]}, {None, 
Directive[
GrayLevel[0.85], 
Thickness[Tiny]]}},
StripOnInput->False]},
{
TagBox[
PopupMenuBox[Dynamic[$CellContext`shp$$], {
             Cone[{{0, 0, -1}, {0, 0, 1}}]->
RowBox[{
             "Cone", "[", "]"}], Sphere[{0, 0, 0}]->
RowBox[{
             "Sphere", "[", "]"}], Cuboid[{0, 0, 0}]->
RowBox[{
             "Cuboid", "[", "]"}], Octahedron[]->
RowBox[{
             "Octahedron", "[", "]"}]}],
HoldForm], "\[SpanFromLeft]"}
},
AutoDelete->False,
BaseStyle->"Output",
BaselinePosition->4,
GridBoxAlignment->{"Columns" -> {{Center}}},
GridBoxItemSize->{"Columns" -> {{5}}, "Rows" -> {Automatic}, "RowsIndexed" -> {3 -> 1, 2 -> 1}},
GridBoxSpacings->{"Columns" -> {{0}}, "Rows" -> {{0}}}],
"Grid"],
PopupMenu[
Dynamic[$CellContext`shp$$], {
Cone[], 
Sphere[], 
Cuboid[], 
Octahedron[]}]],
DynamicModuleValues:>{}],
Setting]\)}, Lighting -> "Accent"]
Out[27]=

Publisher

Edmund B Robinson

Version History

  • 1.0.0 – 25 June 2020

Related Resources

Author Notes

AnnotatedExpression can be used to markup code inline. It enables many inline annotations for documentation, instruction, visualisation, and summary of code and data objects. This can be useful when authoring workflows, course exercises, and several other applications.

License Information