More on "Extracting data points from Plot[]"

*To*: mathgroup at christensen.cybernetics.net*Subject*: [mg959] More on "Extracting data points from Plot[]"*From*: cameron <cameron at dnaco.net>*Date*: Thu, 4 May 1995 03:14:11 -0400

Mathgroupers-- Another post in regard to the subject of using Plot to sample functions. In the development of "The Mathematica Graphics Guidebook", a great deal of material was generated over and above what appeared in the finished book. The project ran enormously over schedule, and we reached a point at which we decided it was better to call a halt and publish a book than to continue making incremental improvements and never get done at all. So we drew a line between core material and nonessential embellishments, polished up the core material, and published it. However, there is much of value in the 150 pages or so of remaining material, even though it was never brought up to publishable form. Coincidentally, one of the examples that got eliminated is the use of Plot and ParametricPlot to sample functions without making a graph -- the same problem that has recently been discussed in this forum. I have attached below an "outtake" from "The Mathematica Graphics Guidebook", in which we define the AdaptiveSample[] function. Share and Enjoy! Best regards-- --Cameron Smith co-author (with Nancy Blachman) of "The Mathematica Graphics Guidebook" P.S. Some of the outtake material from the Guidebook may yet see the light of day, in "The Mathematica Graphics Cookbook". This work -- if we decide to go ahead with it -- would be a companion to the Guidebook. The idea is that the Guidebook is a reference work explaining the concepts underlying Mathematica's graphics model, and the Cookbook would be a compendium of useful examples illustrating the practical use of the model; the relationship would be similar to that between the original PostScript Red and Green books. --------------------------------------------------------------------- The text below is copyright (c) 1995 by Cameron Smith. All rights are reserved. Permission is granted to use the Mathematica code for the AdaptiveSample[] function for any purpose, without fee, at the user's own risk. No warranty, express or implied, is offered. --------------------------------------------------------------------- The adaptive sampling routine used by Plot and ParametricPlot has other uses besides graphing functions -- for example, in certain numerical work it would be nice to be able to say AdaptiveSample[ f, { x, min, max } ] to produce a list of (x,f(x)) pairs with f sampled more densely in intervals over which it is less linear. Mathematica doesn't give us this direct access to its sampling algorithm, but since we know the structure of the graphics objects that Plot and ParametricPlot create, it isn't too hard to write. We simply use one of the plotting functions to prepare a graph of the function, then extract the list of points from the graph and throw the rest away. Here is Mathematica code that does this: SetAttributes[AdaptiveSample,HoldAll]; AdaptiveSample[ f_, {var_, min_, max_}, opts___ ] := Block[ { plot, cmp, pts, bend, div, sampler }, sampler = Plot; If[ MatchQ[ Hold[f], Hold[{_,_}] ], sampler = ParametricPlot ]; {cmp, pts, bend, div} = {Compiled,PlotPoints,MaxBend,PlotDivision} /. {opts} /. Options[sampler]; plot = sampler[ f, {var,min,max}, Compiled -> cmp, PlotPoints -> pts, MaxBend -> bend, PlotDivision -> div, Axes -> None, Frame -> False, DisplayFunction -> Identity, Prolog -> {}, Epilog -> {} ]; First /@ Cases[ First[plot], _Line, Infinity ] ] What's going on here? The SetAttributes command ensures that AdaptiveSample, like Plot and ParametricPlot, defers evaluation of its arguments. In the body of the function, the first thing we have to do is to decide whether to use Plot or ParametricPlot, and we make that choice by examining the first argument: if we were given a pair of functions, we use ParametricPlot, otherwise we use Plot. Next we process the optional arguments, obtaining settings for the four options that control the sampling mechanism (Compiled, PlotPoints, MaxBend, and PlotDivision), and using the default value for each option if no explicit setting was provided. Then we construct a graphics object, setting other options (such as Axes and DisplayFunction) to reduce the amount of unnecessary work done (no point in constructing axes if we aren't going to look at the plot anyway) and to ensure that the graphic isn't displayed. Finally, we extract the Line objects from the list of graphics primitives in the plot, and extract the lists of points from the Line objects. Note that the result of AdaptiveSample is a list of lists of points, rather than simply a list of points. This is necessary, because the result of Plot or ParametricPlot can be a collection of disjoint Line objects. The plotting functions break up their results this way when they detect one or more discontinuities in their arguments, and we want to preserve this information. Here's an illustration of this phenomenon: badfunction[x_] := Which[ x<1, 1, x>2, 2, True, Null ] AdaptiveSample[ badfunction[x], {x,0,3}, PlotPoints -> 10 ] Plot::plnr: CompiledFunction[{x}, <<1>>, -CompiledCode-][x] is not a machine-size real number at x = 1.. Plot::plnr: CompiledFunction[{x}, <<1>>, -CompiledCode-][x] is not a machine-size real number at x = 1.33333. Plot::plnr: CompiledFunction[{x}, <<1>>, -CompiledCode-][x] is not a machine-size real number at x = 1.66667. General::stop: Further output of Plot::plnr will be suppressed during this calculation. {{{0., 1.}, {0.333333, 1.}, {0.666667, 1.}, {0.833333, 1.}, {0.916667, 1.}, {0.958333, 1.}, {0.979167, 1.}, {0.989583, 1.}}, {{2.01042, 2.}, {2.02083, 2.}, {2.04167, 2.}, {2.08333, 2.}, {2.16667, 2.}, {2.33333, 2.}, {2.66667, 2.}, {3., 2.}}} Still, it is true that the result of AdaptiveSample will usually be a list containing a single list of points -- this will always be the case if the function being sampled is continuous over the sampling interval, and will usually be true even if it is not, since the odds are small that the sampler will try to sample a function exactly at an isolated point of discontinuity. ----------------------------------------------------------------------