Chapter IX.  Special Topics

27. Fits and Graphics

Last revision:  April 15 1998

In this last section, we explore Mathematica's graphics commands and "Fit[]" function.

Mathematica operations/structures introduced: 
     ListPlot[]
     Fit[]
     DisplayFunction->Identity
     DisplayFunction->$DisplayFunction
     Show[]
     Graphics[]
     Point[]  Line[]  Rectangle[]  Polygon[]  Circle[]  Disk[]  Raster[]  Text[] 
     Dashing[]  GrayLevel[]  Thickness[]

Fits

Back in the Classroom

Suppose, as we did earlier in the course, that an instructor likes to ask students in a class for answers to homework questions.  If the instructor asks for answers to "n" questions, and there are "m" students in the class, how many different students are likely to be called on?  We can attempt to decide by writing a Mathematica function which mimics this classroom situation.

roster={"Andrews","Biber","Chase","Cowles",
"Dearing","Elzayadi","Ferrentino","Hsieh","Jones",
"Kavanagh","Minlend","Montague","Peay","Smith",
"Sparks","Stovesand","Symes","Talvacchio"};
numStudents = Length[roster];

Clear[draw,numQuestions]
draw[numQuestions_] := Length[
   Union[
     Table[ 
        roster[[ Random[Integer,{1,numStudents}] ]],
        {numQuestions}
     ]
   ]
]

Clear[aveDraw,numCalled,trials]
aveDraw[numCalled_,trials_] := 
   N[ Sum[draw[numCalled],{trials}]/trials ]

The numeric answer may be interesting in its own right, but we may learn more about the function by finding a graphical representation of the function.  We can do so by using "ListPlot[]".  We'll plot the number of questions asked on the x-axis and the resulting average number of different students called upon on the y-axis.

aveData = Table[ 
  {numQuestions, aveDraw[numQuestions,5]},
  {numQuestions,1,100}] ;

dataPlot = ListPlot[aveData]

Unfortunately, on some monitors, the default plot size makes the points too small to see.  If this is true on your monitor, read the rest of the paragraph; otherwise, you may want to skip it.  One solution is to use the option "Prolog->PointSize[.02]" in the "ListPlot[]" call (making it a final parameter), but we must keep in mind that the "PointSize" parameter affects different monitors and printers to differing amounts, so that if we're not careful, the points will print out much larger than they appear on the screen.  Another solution is simply to expand the graphic:  click on the graphic, grab a corner, and drag it to a larger size.  (Note: graphics take up lots of space in on your disk, so you may want to delete cells with graphics before saving.)

After looking at a plot of the data, we may believe that some function approximates the values.  We search for such a function below.

Finding an Analytic Function to Match the Data

What we'd like to do now is "fit" a curve or function to the data in the list "aveData".  In other words, we would like to determine an analytic function, say polynomial, trigonometric, or otherwise, which will match the data points we have.   We might use the function later to guess what some values of data would be, say with a number of questions too large to give to our "aveDraw" function.  The Mathematica function needed is the function "Fit[]".

?Fit

We'll feed the Fit function our list of x-y pairs, a list of "building functions", and the variable we want to use for the function.  Mathematica is allowed to choose any sum of any multiples of the function when finding the "best fit"; i.e., if the building functions are "{f[x], g[x], h[x]}", then "Fit[]" finds the best curve of the form "a f[x] + b g[x] + c h[x]", where "a", "b", and "c" are numbers.

fitter[x_] = Fit[aveData,{1,x,x^2},x]

Here, given building functions "1", "x", and "x^2", the "Fit[]" command finds the best coefficients of all possible curves of the form a*(1) + b*(x) + c*(x^2), i.e. of all possible parabolas.  When your instructor ran this command the result was the sum of 3.82261*(1), .450069*(x), and -.00305751*(x^2). You may find slightly different results because we used the "Random[]" function in creating the list "aveData".   Let's look at the plot.

fitterPlot = Plot[ fitter[x],{x,1,100}]

This doesn't look too much like our previous plot, but one problem is that not the entire graph was shown.  To see the complete graph we need to add the option "PlotRange->All".

Clear[fitterPlot]
fitterPlot = Plot[fitter[x],{x,1,100},
		  PlotRange->All]

This looks a little closer, but let's see how it holds up when we show the function and the data together.

Show[fitterPlot,dataPlot]

That's not too bad, but we can do better by giving the "Fit[]" command more "building functions" with which to construct the approximating function.

Clear[fitter,fitterPlot]

fitter[x_]=Fit[aveData,{1,x,x^2,x^3},x]

fitterPlot=Plot[ fitter[x],{x,1,100},
	PlotRange->All]

Show[fitterPlot,dataPlot]

The real trick to using the "Fit[]" function is in finding good building functions to use.  By doing many experiments, one finds that the "Fit[]" function does very well when given {1,x,1/(x+20)} as building functions.

Clear[fitter,fitterPlot]
fitter[x_]=Fit[aveData,{1,x,1/(x+20)},x]
fitterPlot=Plot[fitter[x],{x,1,100},
	DisplayFunction->Identity]
Show[dataPlot,fitterPlot,
 DisplayFunction->$DisplayFunction]

Note:  the option "DisplayFunction->Identity" suppresses the output of the "Plot[]" function, and "DisplayFunction->$DisplayFunction" forces the output to appear.  (Sometimes this last expression is unnecessary, but remembering to use it when "DisplayFunction->Identity" is used is wise.)

Graphics, Primitives

Showing by Doing, Doing by Showing

We will build up the pieces of this picture one at a time and then use "Show[]" to display them at the same time.  First, we must tell Mathematica that we will need the package of color definitions.  This command should be executed only once, before any other cells using color names are executed, so that no color names will be defined in the "Global`" context before these definitions are executed.

Needs["Graphics`Colors`"]

If we want to see all the colors we can use, we can execute the following cell.

?Graphics`Colors`*

In order to create the red triangle, we will use our first graphics primitive.  A graphics primitive is a symbolic graphics command, which for 2-dimensional graphics are chosen from "Point[]", "Line[]", "Rectangle[]", "Polygon[]", "Circle[]", "Disk[]", "Raster[]", and "Text[]".  We will also use a graphics directive, which for us will either be a color command or a "dashing instruction", which we will define below.  The difference between primitives and directives lies in the fact that graphics primitives describe particular geometric objects,while graphics directives specify only characteristics of succeeding primitives.  If we place graphics primitives and directives together in a list, the graphics directives set the characteristics for all succeeding primitives (unless another directive which negates the action is encountered).  After we create a list of primitives and directives, we will need two commands which will actually create the graphics based on the commands in our list.  One command is needed for each of the two stages of the process.  The first command, "Graphics[]", converts graphics directives and primitives into Mathematica's own internal commands for the graphics.  However, this command does not display the graphics.  The second command, "Show[]", takes the internal commands created by "Graphics[]" and actually displays them in a cell.  It is important that we store the result of "Graphics[]", these internal commands, in some variable, so that we can execute "Show[]" with this variable as a parameter.

We build up the picture as follows.  Our red triangle is formed by first issuing the graphics directive "Red", followed by the graphics primitive "Polygon[]", which takes as its argument a list of x-y pairs, thought of as the vertices of the polygon.

redTriangle=Graphics[{Red,Polygon[{{0,0},{1,0},{1,1}}]}]

We'll now define a disk (a filled-in circle) and a circle.  These primitives require two arguments, an x-y pair, followed by the radius of the circle.

purpleDisk=Graphics[{Purple,Disk[{0,1},.25]}]

yellowCircle=Graphics[{Yellow,Circle[{1,1},.25]}]

We may display any combination of our primitives now by using the "Show[]" command.

Show[redTriangle, purpleDisk, yellowCircle]

Our primitives appear squashed because of the default "aspect ratio", which forces the "y" axis to be scaled in accordance with "x".  To circumvent this, we can tell Mathematica to figure out the correct aspect ratio to display x-y points with even scaling in the x and y directions, using the option "AspectRatio->Automatic".

Show[redTriangle, purpleDisk, yellowCircle,
   AspectRatio->Automatic
]

Now we will construct a box, where the lines are not solid but are "dashed", using a separate graphics directive "Dashing[]".  This directive requires as arguments a list of lengths for the dashed segments of the line; the list will be repeated over and over to determine the length of each dashed piece.  Giving "Dashing[]" a list with one element, then, specifies that the dashing segments will all be of the same length.  Our graphics primitive is "Line[]", which requires a list of x-y pairs to connect; note that we close off the list with the same point we began with.

box=Graphics[{Goldenrod,Dashing[{.01}],
    Line[{{0,1},{1,0},{2,1},{1,2},{0,1}}]}]

Finally we introduce some text, using the graphics primitive "Text[]", which takes as arguments a string to be printed and an x-y pair describing the coordinate at which the text should be centered.

tagLine=Graphics[{Text["Soda Shop or Cosmic Coffee?",{1,1.5}]}]

Voila!

masterPiece = Show[
  redTriangle,purpleDisk,yellowCircle,box,tagLine,
  Axes->True,
  AspectRatio->Automatic
]

Adding Plots to Graphics

Suppose we want to add the graphics resulting from a plot command to a picture we have built up using graphics primitives.  We need only capture the internal representations of the graphics, by assigning the results of the "Graphics[]" command and the "Plot[]" or "ListPlot[]" command to separate variables, and we then use "Show[]" to display all of the graphics together.

sine = Plot[1+Sin[Pi x],{x,0,2}]

This command actually shows the graph, but remember that we can suppress the immediate display by using the "DisplayFunction->Identity" option.  Remember to use "DisplayFunction-> $DisplayFunction" with the "Show[]" command.

minusSine = Plot[1-Sin[Pi*x],{x,0,2}, 
   DisplayFunction->Identity]

Show[masterPiece, sine, minusSine,
   DisplayFunction->$DisplayFunction]

Adding Graphics to Plots

Alternatively, we can attempt to add graphics to the result of the "Plot[]" command.  We can do so using the options "Prolog[]" or "Epilog[]", which provide "Plot[]" with some graphics primitives it must display both before and after the original plot.  We do not need to use the "Graphics[]" function.

Plot[1+Sin[Pi x],{x,0,2}, 
   Epilog->
      {Purple,
       Disk[{0,1},.25],
       Red,
       Circle[{1,1},.25]}
]

Let's change "Epilog" to "Prolog".  Is there a difference?  Why?

Plot[1+Sin[Pi x],{x,0,2}, 
   Prolog->
      {Purple,
       Disk[{0,1},.25],
       Red,
       Circle[{1,1},.25]}
]

Further Study

The wealth of graphics primitives and directives is too large for us to consider exhaustively here.  However, here are some tips you may wish to remember when using "Plot[]" or some other plot command.

The option "PlotStyle->{ }" provides a way for graphics directives to be issued before a function is plotted.  If the list contains sublists, then sublists of directives are used, one at a time, for each function.  To plot "x^2" in red and "x^3" in green, then, we could issue the command "Plot[{x^2,x^3},PlotStyle->{{Red},{Green}}]".

Other directives include "GrayLevel[]", for gray-scale "color", and "Thickness[]", to alter the widths of the lines drawn.

Options for plot commands also include "Axes->boolean" to decide whether or not to draw the axes; "GridLines->..." for drawing gridlines, and "PlotLabel->"text"" to assign a label to the plot.  Consult "Options[Plot]" for more information.

Finally, Mathematica easily plots three-dimensional graphs using 3-D graphics primitives and "Graphics3D[]".  Consult Introduction to Programming with Mathematica, chapter 10, or the Mathematica reference manual, for further study.