Non-Trivial Graphics in Mathematica
by Theodore W. Gray

Producing complex and beautiful two and three dimensional graphics using the functions Plot, Plot3D, ContourPlot, DensityPlot, etc is trivial in Mathematica.  
     In this Notebook we will concentrate on the less well known Graphics and Graphics3D functions, which allow much finer control over the graphics produced by Mathematica.

Introduction to Graphics Primitives

Mathematica defines a set of primitive graphics objects you can use to build up complex pictures.  For example, the following draws a line and a filled polygon:

Show[Graphics[
		{
		Line[{{0, 0}, {4, 4}}],
		Polygon[{{1, 1}, {1, 3},
		 		 {3, 3}, {3, 1}}]
		}
	]]

The function Graphics takes a list of graphics primitives and labels them as graphical objects.  The function Show actually displays the objects as PostScript graphics.
     You can use the full power of Mathematica in producing the list of graphics objects.  For example, the following displays a bunch of random lines:

Show[Graphics[
	Table[Line[{{Random[], Random[]},
				{Random[], Random[]}}],
		  {50}]
	]]

A slight variation shows a random filled polygon:

Show[Graphics[Polygon[
	 Table[{Random[], Random[]}, {50}]
	 ]]]

By simply substituting Graphics3D for Graphics and adding a third dimension to each coordinate, we can produce 3D graphics:

Show[Graphics3D[
	Table[Polygon[
   			Table[{Random[], 
   				   Random[], 
   				   Random[]}, 
				  {5}]
    			],
    	 {4}]
    ]]

Using Graphics Primitives

As an example of using 2D graphics primitives, let's define a simple alternative to the Plot command.  Plot always draws one or more lines representing function values.  Let's make a function which fills in the area beneath a function instead.
     We start by making a function which simply produces a list of values from a function and range.

Clear[FillPlot];
FillPlot[f_, {x_, xmin_, xmax_}] := 
	Table[N[{x, f}], 
	  {x, xmin, xmax, (xmax-xmin)/15}]

Let's try it:

FillPlot[BesselJ[0, x], {x, 0, 8}]

Now we can modify our function to actually draw the line defined by these points:

Clear[FillPlot];
FillPlot[f_, {x_, xmin_, xmax_}] := 
	Show[Graphics[
		Line[
			Table[{x, f}, 
				  {x, xmin, xmax, 
				   (xmax-xmin)/15}]
			]
		], Axes->Automatic]

FillPlot[BesselJ[0, x], {x, 0, 8}]

We now have a simple version of Plot, but that's not what we really wanted.  To make a filled area instead of a line, we will use Polygon instead of Line:

Clear[FillPlot];
FillPlot[f_, {x_, xmin_, xmax_}] := 
	Show[Graphics[
		Polygon[
			   Table[{x, f}, 
					 {x, xmin, xmax, 
				 	  (xmax-xmin)/15}]
			   ]
		], Axes->Automatic]

FillPlot[BesselJ[0, x], {x, 0, 8}]

Of course, this is not quite right.  We need to add two more points to define the baseline:

Clear[FillPlot];
FillPlot[f_, {x_, xmin_, xmax_}] := 
	Show[Graphics[
		Polygon[Join[
			{{xmin, 0}},
			 Table[{x, f}, 
			 	   {x, xmin, xmax, 
					(xmax-xmin)/15}],
			{{xmax, 0}}]
			   ]
	], Axes->Automatic]

FillPlot[BesselJ[0, x], {x, 0, 8}]

That's what we want.  This version has a number of drawbacks, most notably that the number of sample points is fixed at 15.  We could add an option to the function to allow you to choose the number of sample points, but this is not the best approach.
     The built-in Plot command uses a clever adaptive sampling method to give smooth plots for most functions.  We would like to use the same method for out FillPlot command.  We can do this by using the fact that the function result of Plot contains a list of all the points sampled.  We can use the following trick to get out this list:

Plot[BesselJ[0, x], {x, 0, 8},
DisplayFunction->Identity][[1,2,1,1]]

As you can see, Plot uses a lot more than 15 sample points to get a smooth curve.  Using this trick, we can make a new version of FillPlot:

Clear[FillPlot];
FillPlot[f_, {x_, xmin_, xmax_},
		 options___] := 
  Show[Graphics[
	Polygon[Join[
			{{xmin, 0}},
			Plot[f, {x, xmin, xmax},
			DisplayFunction->Identity
						][[1,2,1,1]],
			{{xmax, 0}}
				]
		   ]
	  ], Axes->Automatic, options]

FillPlot[BesselJ[0, x], {x, 0, 8}]

This version is pretty good.  We have also allowed an options arbitrary number of extra arguments, which are simply passed on to Show.  This allows you to, for example, set the plot range manually.  We will use this feature in the next section.

Adding Motion

Once you have defined a function which produces graphics, it is relatively easy to create animations using it.  For example, we can make an animation using the FillPlot function defined in the section above:

Do[FillPlot[BesselJ[n, x], {x, 0, 20},
			PlotRange->{-0.4, 0.65}], 
   {n, 1, 10, 0.2}];

As a final example, we will define a function which automatically produces an animation.  We will call it SpinFillPlot.

Clear[SpinFillPlot];
SpinFillPlot[function_, 
			 range_,
			 options__] :=
	Do[FillPlot[n function, 
				range, options],
	   {n, 1, -1, -2/15}]

SpinFillPlot[BesselJ[1, x], 
			 {x, 0.001, 20},
			 PlotRange->{-0.65, 0.65}];