How could we display the position of any sub expression in an expression using Tooltip?

This would be useful for example in order to locate the position of an element in the FullForm of a Plot.

I think I saw a similar Q&A once, but I haven't found it again.


The answer of Kuba is very instructive. Here is the function I had in mind which is a variation of Kuba's answer.

labelPositions[graphics_] := Fold[Function[{plot, pos}, MapAt[Tooltip[#, pos] &, plot, pos]], graphics, Position[graphics,_,Infinity]] 

Using Kuba's comment, even simpler

labelPositions[graphics_]:= MapIndexed[Tooltip,graphics,Infinity, Heads -> True]
  • $\begingroup$ What do you mean by "the position"? Please give a specific example. $\endgroup$ Jan 25 '16 at 20:56

We have to use Is there a GraphicsPrimitiveQ (or a complete list of Heads of graphics primitives)?

primitivesQ = MatchQ[#, 
    Alternatives @@ {Point, PointBox, Line, LineBox, Arrow, ArrowBox,           Rectangle, RectangleBox, Parallelogram, Triangle, JoinedCurve,           JoinedCurveBox, FilledCurve, FilledCurveBox, StadiumShape,           DiskSegment, Annulus, BezierCurve, BezierCurveBox, BSplineCurve,           BSplineCurveBox, BSplineSurface, BSplineSurface3DBox,           SphericalShell, CapsuleShape, Raster, RasterBox, Raster3D,           Raster3DBox, Polygon, PolygonBox, RegularPolygon, Disk, DiskBox,           Circle, CircleBox, Sphere, SphereBox, Ball, Ellipsoid,           Cylinder, CylinderBox, Tetrahedron, TetrahedronBox, Cuboid,           CuboidBox, Parallelepiped, Hexahedron, HexahedronBox, Prism,           PrismBox, Pyramid, PyramidBox, Simplex, ConicHullRegion,           ConicHullRegionBox, Hyperplane, HalfSpace, AffineHalfSpace,           AffineSpace, ConicHullRegion3DBox, Cone, ConeBox, InfiniteLine,           InfinitePlane, HalfLine, InfinitePlane, HalfPlane, Tube, 
      TubeBox, GraphicsComplex, GraphicsComplexBox, GraphicsGroup,           GraphicsGroupBox, GeoGraphics, Graphics, GraphicsBox,           Graphics3D, Graphics3DBox, MeshRegion, BoundaryMeshRegion,           GeometricTransformation, GeometricTransformationBox, Rotate,           Translate, Scale, SurfaceGraphics, Text, TextBox, Inset,           InsetBox, Inset3DBox, Panel, PanelBox, Legended, Placed,           LineLegend, Texture}
    ] &;


labelPositions[graphics_] := Fold[
  Function[{plot, pos}, 
   MapAt[Tooltip[#, Column@{Head[#], pos}] &, plot, pos]],
  Position[graphics, x_[___] /; primitivesQ[x], \[Infinity]]


plot = Graphics[{Thick, Green, Rectangle[{0, -1}, {2, 1}], Red, 
    Disk[], Blue, Circle[{2, 0}], Yellow, 
    Polygon[{{2, 0}, {4, 1}, {4, -1}}], Purple, Arrowheads[Large], 
    Arrow[{{4, 3/2}, {0, 3/2}, {0, 0}}], Black, Dashed, 
    Line[{{-1, 0}, {4, 0}}]}];

labelPositions @ plot

enter image description here


This is done with an assumption that primitives are not nested within others. In general that's not true, like for FilledCurve @ BSplineCurve[...] so those cases should be handled with more care.

  • $\begingroup$ This is very impressive. I modified your function to suit what I wanted, ie to get the position of any component of an expression represented in FullForm: labelPositions[graphics_] := Fold[Function[{plot, pos}, MapAt[Tooltip[#, pos] &, plot, pos]], graphics, Position[graphics, x_, Infinity]] $\endgroup$
    – faysou
    Jan 25 '16 at 22:45
  • $\begingroup$ I realized with your answer, it would be quite practical if MapAt had the position in #2 as argument similarly to MapIndexed. Maybe one day, or maybe not, as maybe this could have an impact on performance, I don't know. $\endgroup$
    – faysou
    Jan 26 '16 at 8:43
  • $\begingroup$ @faysou yep, but what about: MapIndexed[If[#2[[-1]] == 0, Tooltip[##], #] &, plot , {1, \[Infinity]}, Heads -> True] $\endgroup$
    – Kuba
    Jan 26 '16 at 8:48
  • $\begingroup$ Looks good ! Thanks $\endgroup$
    – faysou
    Jan 26 '16 at 23:16

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.