26
$\begingroup$

For various reasons related to workflow associated with creating figures for journals, I am creating functions that will accept graphics primitives and a set of options and spit out a Graphics object with those primitives and those options in some configuration.

(Of course, this sounds like all I'm doing is re-creating Graphics, in that I can call

Graphics[ <List of primitives>, <Sequence of options>] 

but it's more complicated than that.)

In any case, I would like to be able to check whether the inputs to the function are graphics primitives or not. We can create our own GraphicsPrimitiveQ if we have a list of the Heads of graphics primitives. For instance,

Clear[GraphicsPrimitiveQ, listOfHeads] listOfHeads = {Line, Polygon, Point, Arrow, Tube}; GraphicsPrimitiveQ[x_] := MatchQ[Head[x], Alternatives @@ listOfHeads] 

in which case if we define

f[x__?GraphicsPrimitiveQ] := {x} 

then

f[Point[{0, 0}], Line[{{1, 1}, {0, 0}}]] (* {Point[{0, 0}], Line[{{1, 1}, {0, 0}}} *) 

and

f[Point[{0, 0}], 1] (* f[Point[{0, 0}], 1] *) 
  • So: Is there something like a GraphicsPrimitiveQ?

  • Or: Is there hidden somewhere in Mathematica an easy way to get a list of all graphics primitives?

  • Alternatively, if there's no built-in ListOfGraphicsPrimitives[], then Is there a programmatic way of making the function GraphicsPrimitiveQ? (Added this because I for some reason didn't anticipate the clever answers below.)

$\endgroup$
5
  • 3
    $\begingroup$ Here's a parser I wrote for work. It has an almost complete list of primitives and directives. All that it is missing is the new stuff for 10.2. $\endgroup$ Commented Jul 15, 2015 at 21:15
  • $\begingroup$ @rcollyer. I saw this answer in my search before posting the question! I was hoping for something that could be called directly from Mathematica, but I can always deposit your primitives in a package if I need to. Thanks! $\endgroup$ Commented Jul 15, 2015 at 21:19
  • $\begingroup$ I think I have something that will work, programatically. $\endgroup$ Commented Jul 15, 2015 at 21:20
  • $\begingroup$ In the old days, I had to maintain a long list based on the list given in the docs. I like this question; maybe you should also ask about the possibility of a GraphicsDirectiveQ[]. :) $\endgroup$ Commented Jul 16, 2015 at 0:32
  • $\begingroup$ @march correction, now the parser has a complete list of primitives. I forgot to add the v10 and v10.2 primitives even in my local implementation. $\endgroup$ Commented Jul 16, 2015 at 13:02

4 Answers 4

22
$\begingroup$

Edit: It was pointed out that the original form is not bullet-proof, e.g. GraphicsPrimitiveQ /@ {InputNotebook, Unique, Sequence} all returned True. However, when looking upon this answer about generating new graphics primitives, a superior answer came to light:

Clear[GraphicsPrimitiveQ]; GraphicsPrimitiveQ[s_Symbol | (s_)[___]] := 0 < Count[DownValues[Typeset`MakeBoxes], Verbatim[HoldPattern][HoldPattern[Typeset`MakeBoxes[s[___], __, Graphics]]], -1] 

which is now bullet-proof:

GraphicsPrimitiveQ /@ {Rectangle, Pyramid, Sequence} (* {True, False, False} *) 

I need to look deeper for one dealing with Graphics3D, though.


This is the old version. It works, but has issues.

This works for Graphics primitives:

Clear[GraphicsPrimitiveQ]; GraphicsPrimitiveQ[s_Symbol] := !MatchQ[ToBoxes@Graphics[s[]], GraphicsBox[_s]] GraphicsPrimitiveQ /@ {Line, Bob, CapsuleShape (*3d primitive*)} (* {True, False, False} *) 

with the additional rule

GraphicsPrimitiveQ[e : (h_)[___]] := !MatchQ[ToBoxes@Graphics[e], GraphicsBox[_h]] GraphicsPrimitiveQ[#[{{1,2},{3,4}}]]& /@ {Polygon, List} (* {True, False} *) 

This works because in the presence of Graphics, the primitives have a box form, e.g.

ToBoxes@Graphics@Line[{{1,2},{3,4}}] (* GraphicsBox@LineBox[{{1,2},{3,4}}] *) 

but non-primitives do not, even those that have box forms

ToBoxes@Subscript[x, 2] (* SubscriptBox[x, 2] *) ToBoxes@Graphics@Subscript[x, 2] (* GraphicsBox[Subscript[x, 2]] *) 

nor do primitives expand to their box form outside of Graphics, e.g.

ToBoxes@Line[] (* RowBox[{"Line", "[", "]"}] *) 

We can do the same with Graphics3D,

Clear[GraphicsPrimitiveQ]; Graphics3DPrimitiveQ[s_Symbol] := !MatchQ[ToBoxes@Graphics3D[s[]], Graphics3DBox[_s]] Graphics3DPrimitiveQ[e : (h_)[___]] := !MatchQ[ToBoxes@Graphics3D[e], Graphics3DBox[_h]] 

but it returns True for exclusively 2D primitives, e.g.

Graphics3DPrimitiveQ @ Rectangle (* True *) 

So, I do not know how to approach this, if you want something that will exclusively detect 3D primitives.

$\endgroup$
13
  • $\begingroup$ That's... mysterious. I'll try to parse that later. In the meantime, +1. (I'm out of votes for the day, but I'll upvote in a couple of hours.) I will need it to find 3D primitives, in general. Also, in order to match the primitive and not just the Head, could we do instead GraphicsPrimitiveQ[s_Symbol[__]]? $\endgroup$ Commented Jul 15, 2015 at 21:36
  • 1
    $\begingroup$ @Mr.Wizard well, it's a good thing I found a better way. I'll post it shortly, I hope. $\endgroup$ Commented Jul 16, 2015 at 2:33
  • 1
    $\begingroup$ Using your own list of primitives from (32719) reveals that GraphicsPrimitiveQ fails more often that it succeeds. In 10.1.0 failures are: {AASTriangle, ASATriangle, BezierCurve, BSplineCurve, BSplineSurface, Circle, Circumsphere, Cone, Cylinder, Disk, EmptyRegion, FullRegion, Hexahedron, Parallelepiped, Parallelogram, Polygon, Prism, Pyramid, Raster, Raster3D, SASTriangle, SSSTriangle, Tetrahedron, Tube} $\endgroup$ Commented Jul 16, 2015 at 13:35
  • 1
    $\begingroup$ You'll notice the conspicuous lack of an answer from me. Happy fiddling! ;-) $\endgroup$ Commented Jul 16, 2015 at 13:54
  • 1
    $\begingroup$ I decided to post the only simple answer I can think of. It's not a good match for what the OP requested but I think it has potentially useful behavior of its own. I expect you'll inform me of its failings. :-) $\endgroup$ Commented Jul 16, 2015 at 14:24
11
$\begingroup$

With WolframLanguageData your list of graphics primitives will stay up to date.

ListOfGraphicsPrimitives[] = Symbol /@ WolframLanguageData[ EntityClass["WolframLanguageSymbol", {"FunctionalityArea","GraphicsPrimitiveFunctions"}], "Name"] 

{AASTriangle, AffineHalfSpace, AffineSpace, Annulus, Arrow, ASATriangle, Ball, BezierCurve, BSplineCurve, CapsuleShape, Circle, Circumsphere, Cone, ConicHullRegion, Cuboid, Cylinder, Disk, DiskSegment, Ellipsoid, EmptyRegion, FilledCurve, FullRegion, GraphicsComplex, HalfLine, HalfPlane, HalfSpace, Hexahedron, Hyperplane, Insphere, JoinedCurve, Line, Parallelepiped, Parallelogram, Point, Polygon, Prism, Rectangle, RegularPolygon, SASTriangle, Simplex, Sphere, SphericalShell, SSSTriangle, StadiumShape, Tetrahedron, Triangle, Tube}

ListOfGraphicsFunctions[] = Symbol /@ WolframLanguageData[ EntityClass["WolframLanguageSymbol", {"FunctionalityArea","GraphicsFunctions"}], "Name"] 

{AbsoluteDashing, AbsolutePointSize, AbsoluteThickness, Antialiasing, Arrowheads, AspectRatio, Axes, AxesEdge, AxesLabel, AxesOrigin, AxesStyle, Axis, Back, Background, BezierFunction, BoundaryDiscretizeGraphics, Boxed, BoxRatios, BoxStyle, BSplineFunction, BSplineSurface, CapForm, ClippingStyle, ClipPlanes, ClipPlanesStyle, ClipRange, ContentSelectable, ContourLabels, Contours, ContourShading, CoordinatesToolOptions, CurveClosed, Dashing[{Small, Small}], Dashing, DataRange, DataReversed, DateTicksFormat, DefaultAxesStyle, DefaultBaseStyle, DefaultBoxStyle, DefaultFaceGridsStyle, DefaultFrameStyle, DefaultFrameTicksStyle, Directive, DiscretizeGraphics, DisplayFunction, Dashing[{0, Small, Small, Small}], Dashing[{0, Small}], EdgeForm, Epilog, Exclusions, ExtentElementFunction, ExtentMarkers, ExtentSize, FaceGrids, Filling, FillingStyle, Frame, FrameLabel, FrameMargins, FrameTicks, Front, FullGraphics, Graphics, Graphics3D, GraphicsColumn, GraphicsGrid, GraphicsGroup, GraphicsRow, GridLines, Inset, ItemAspectRatio, Joined, Lighting, LightingAngle, Mesh, MeshFunctions, MeshShading, NCache, NormalsFunction, Offset, Opacity, OpacityFunction, OpacityFunctionScaling, PixelConstrained, PointSize, PolarAxes, PolarAxesOrigin, PolarGridLines, PolarTicks, Prolog, Raster, Raster3D, Rasterize, RasterSize, RegionFunction, RevolutionAxis, Rotate, RotateLabel, RotationAction, RoundingRadius, Scale, Scaled, Show, Specularity, SphericalRegion, SplineClosed, SplineDegree, SplineKnots, SplineWeights, StreamScale, Texture, Thickness[Large], Thickness, Thickness[Tiny], Ticks, Translate, GrayLevel[ 0, 0], VertexColors, VertexDataCoordinates, VertexNormals, VertexTextureCoordinates, ViewAngle, ViewCenter, ViewMatrix, ViewPoint, ViewRange, ViewVector, ViewVertical}

Hop this helps.

$\endgroup$
2
  • $\begingroup$ I tried to get this yesterday, but I think I will need a lot of time till I get intuition how to work entities :-/ $\endgroup$ Commented Jan 26, 2016 at 7:13
  • $\begingroup$ On my Mac with v11.3, ListOfGraphicsPrimitives gives me different results than shown here and does not include the following primitives listed in the documentation for Graphics: Disk, InfiniteLine, Inset, GraphicsGroup, Line, Locator, Point, Polygon, Raster, SASTriangle, and Text. The bolded entries are also not in your results. $\endgroup$ Commented Oct 15, 2018 at 0:51
10
$\begingroup$

The answer to the question depends upon what exactly should be called as "graphics primitive". In this answer from the practical point of view I define it as a container which can be found inside of Graphics or Graphics3D, which draws something and is not a graphical directive or Dynamic wrapper. This definition differs from the usual meaning but covers all the key cases. Here is (I hope) complete list of such containers for version 10.2:

{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}

$\endgroup$
7
$\begingroup$

Since there seems no other simple answer at this time I propose the approach of rendering a Graphics expression and seeing if it has errors. By definition this will pass both primitives and directives, as well as inert expressions such as {}. I hope it nevertheless serves some purpose.

I rasterize the graphic and look for the tell-tale pink warning color. Of course it would be easy to create a false negative simply by creating an element with this very color but that is a corner case.

graphicsQ = FreeQ[Union @@ ImageData @ Image[Graphics[#], ImageSize -> 30], x_ /; x == {1.`, 0.9019607843137255`, 0.9019607843137255`}] &; 

Positive examples:

graphicsQ /@ {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}}]} 

{True, True, True, True, True, True, True, True, True, True, True, True, True, True, True}

Some negative examples:

graphicsQ /@ {Circle["x"], Arrow[], Line[], Pi, 2.2} 

{False, False, False, False, False}

Specifically I included malformed primitives to demonstrate that these are not passed. This may or may not be desirable depending on your application.

$\endgroup$
4
  • 1
    $\begingroup$ The pink color works, but I think the superior method is to adapt this answer, and yes this was my ultimate fall back method. $\endgroup$ Commented Jul 16, 2015 at 14:26
  • $\begingroup$ @rcollyer I'm sad to say I forgot about that answer! Would you like to post a second answer using that method and I shall delete mine? $\endgroup$ Commented Jul 16, 2015 at 14:29
  • 1
    $\begingroup$ I'll might do that this afternoon. I might edit yours. Neither will happen until this afternoon. :P $\endgroup$ Commented Jul 16, 2015 at 14:34
  • 1
    $\begingroup$ I think the fact that it outputs False for malformed primitives (something that I didn't think of) is extremely useful, for a number of reasons, so this is a good addition. $\endgroup$ Commented Jul 16, 2015 at 16:40

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.