Re: Extracting data points from Plot[]
- To: mathgroup at christensen.cybernetics.net
- Subject: [mg782] Re: Extracting data points from Plot[]
- From: villegas (Robert Villegas)
- Date: Wed, 19 Apr 1995 00:26:50 -0400
- Organization: Wolfram Research, Inc.
> The Plot[] function does some intelligent picking of points, such that it > usually does a pretty good job of following twists and turns in a function > without plotting an excessive number of points. I'm not ecstatic about > using Mma for final output, though, so I like to export these curves to a > graphing program. .. > What I'm wondering, though, is if there isn't something a bit more > straightforward than "InputForm[%1][[1]][[1]][[2]][[1]][[1]][[1]]" to get > at the data points? Is there a way to generate these data series the way > Plot[] does, without using Plot (which necessitates stripping off the > "Graphics" and "Line" structures which make up the bulk of the > sub-sub-sub-arrays that I'm referencing). Fortunately, there is no need to try to pin-point the Line structures yourself. One thing you can do is save the samples that Plot chooses by appending each one to some list. If you're plotting f[x] on the interval [a, b] you can do: samples = {} Plot[ (AppendTo[samples, {x, f[x]}]; f[x]), {x, a, b}, DisplayFunction->Identity ]; Now 'samples' will contain all the sample points that Plot generated while working toward a Plot, and in the same order in which Plot generated them. Since Plot uses an adaptive sampling routine that sometimes goes back over an interval and samples it more finely, the list of points in 'samples' may not always progress from left to right. Don't forget to include "samples = {}" in each evaluation you do, otherwise 'samples' will keep accumulating points from previous Plot's. (This method is given in the Course Notes _Numerical Computation in Mathematica_ by Jerry Keiper and Dave Withoff, on page 1. It is also given, in the context of a thorough description of Plot's adaptive sampling, in Tom Wickham-Jones' book _Mathematica Graphics: Techniques & Applications_, p. 583. The same method can be used for other iterative commands like NIntegrate and FindRoot) If f is expensive to compute, then you may not want to evaluate it twice like I did above. You can use a pure function that will put f[x] to use twice, once for the AppendTo that does the record-keeping, and once as the return value of the whole function: Plot[ (AppendTo[samples, {x, #}]; #)& [ f[x] ], {x, a, b}, DisplayFunction->Identity ]; This gives up some simplicity of appearance for efficiency when the latter is more important. This will give you the entire set of values that Plot _tried_ in the course of sampling, but sometimes Plot will throw out points, say if the function doesn't evaluate to a real number at some of them. For instance, Sqrt[x^2 - 4] isn't real on (-2, 2), so if you plot it on [-3, 3], there will be two disconnected curves, hence two separate Line objects. You can use Cases to find the Line objects and pull out their points, without having to know exactly where they are in the Graphics expression. In[60]:= p = Plot[Sqrt[x^2 - 4], {x, -3, 3}] [... error messages deleted ...] Out[60]= -Graphics- In[61]:= subcurves = Cases[First[p], Line[pts_List] :> pts, -1] Out[61]= {{{-3., 2.23607}, {-2.75, 1.88746}, {-2.5, 1.5}, {-2.375, 1.28087}, [ ...some lines deleted... ] {2.25, 1.03078}, {2.5, 1.5}, {2.75, 1.88746}, {3., 2.23607}}} If the function is well-behaved throughout the interval and there is just one Line object, then First[subcurves] will give you a list of pairs. Really, 'Cases' is a general command to extract all pieces of an expression that have a certain structure or possess certain properties; this is just one small application. See p. 221 of The Mathematica Book for more on it. Robby Villegas