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.

  • 2
    $\begingroup$ plt //. _[___, x_Line, ___] :> x $\endgroup$ – Kuba May 27 '14 at 19:35
  • 1
    $\begingroup$ @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]]]. $\endgroup$ – mfvonh May 27 '14 at 19:58
  • 6
    $\begingroup$ 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. $\endgroup$ – Szabolcs May 27 '14 at 20:44
  • 1
    $\begingroup$ 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. $\endgroup$ – rcollyer May 28 '14 at 0:41
  • 1
    $\begingroup$ Related to Szabolcs's comment, and possibly of interest: (9209), (9233) $\endgroup$ – Mr.Wizard May 28 '14 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

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 /@
   plt2 /. Line[data_] :> RuleCondition @ Sow @ data;
 ][[2, 1]]

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.)

  • $\begingroup$ Concise and enlightening, you have my gratitude! $\endgroup$ – saturasl May 28 '14 at 18:13
  • $\begingroup$ 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. $\endgroup$ – saturasl May 28 '14 at 18:24

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.