# Extracting graphics primitives from a Graphics expression with ReplaceAll

If we have a graphics object,

plt = Plot[Sin[x], {x, 0, Pi}]


and we need to retrieve the discrete point data from it. This can be easily done by using Extract and Position,

First@Extract[plt, Most@First@Position[plt, Line]]


Or using Cases,

First@Cases[plt, Line[data_] -> data, Infinity]


However, my question is, might this be done via generic pattern matching? For example, some code like

plt /. (patterns-for-any-nested-or-parallel-heads) __ [ ___, Line[data_], ___] :> data


It might not be difficult to handle the parallel heads, but I do not see a obvious way to deal with the nested heads in a generic manner. Of course we can manually type all the nested heads, but this is rather specific. I am exploring the capacity of pattern matching in Mathematica. Is it possible to figure a general way to make Mathematica does it by itself? Actually I think this might be part of the algorithm under the hood of Cases.

• plt //. _[___, x_Line, ___] :> x
– Kuba
May 27, 2014 at 19:35
• @saturasl @Kuba's way is how I would do it with patterns, but I understand what you're asking. I don't know how to achieve that with /. (I'll mull it over.) But concerning your original question, I don't think that is how Cases is implemented. My guess is the algorithm looks more like Reap[Scan[If[MatchQ[#, _Line], Sow[#]] &, plt, \[Infinity]]]. May 27, 2014 at 19:58
• It is appropriate to point out an important difference between Cases and Replace(All) here. The former walks the expression tree from inside out (leaves first, root last), while ReplaceAll goes the other way: outside first, then the leaves of the tree last. Yes, one of them can emulate the other, but this difference will always persist. *Also: Your question implies that ReplaceAll is somehow more fundamental ("generic pattern matching") than Cases. I wouldn't say this is the case and I'm pretty sure internally one isn't implemented in terms of the other. May 27, 2014 at 20:44
• The most effective method is to use Cases which is what I use. A Graphics object describes a state machine, and if you want something that captures the structure, use a parser. But, usually that is overkill, so stick with Cases. May 28, 2014 at 0:41
• Related to Szabolcs's comment, and possibly of interest: (9209), (9233) May 28, 2014 at 6:44

Other than the fact that ReplaceAll and Cases traverse expressions differently, as mentioned by Szabolcs in a comment (see (9209), (9233)), you could use Throw and Catch:

r1 = First@Cases[plt, Line[data_] :> data, Infinity];

r2 = plt /. Line[data_] :> Throw[data] // Catch;

r1 === r2

True


For multiple matches you could use Sow and Reap, along with RuleCondition to handle held expressions, as in:

plt2 = Plot[{Sin[x], Cos[x], Sinc[x]}, {x, 0, 5}];

Short /@
Reap[
plt2 /. Line[data_] :> RuleCondition @ Sow @ data;
][[2, 1]]

{{{1.02041*10^-7,1.02041*10^-7},<<405>>,{5.,-0.958924}},
{{1.02041*10^-7,1.},<<335>>,{5.,0.283662}},
{{1.02041*10^-7,1.},<<325>>,{5.,-0.191785}}}


If for some reason you don't want to use Throw, Catch, Sow, or Reap you could manually accumulate these expressions, but there is little point in such an exercise as far as I can see. (Or you could use the lower-level StuffBag if that interests you.)

• Concise and enlightening, you have my gratitude! May 28, 2014 at 18:13
• Throw, Catch, Sow, and Reap can be used almost anywhere in any code, such powerful attribute might also be heavily used in the built-in code of Trace, and I think they are at very fundamental level of Mathematica language. May 28, 2014 at 18:24