Basic Plotting

from Essential Mathematica for Students of Science
© James J. Kelly, 1998
Last revised: January, 2004

Introduction

Mathematica provides a collection of plotting tools that rival those of many packages dedicated to that single purpose.  Although many plotting packages provide friendlier user interfaces, Mathematica is unique in its integration of graphics with numerical, symbolic, and typesetting capabilities.  Some of the awkward features of the plotting commands can be attributed to the integration of all of these capabilities within a uniform structure.  Hence, although it is almost trivial to obtain quick plots, producing publication-quality figures requires choosing many rather verbose options and may take a lot of time.  Nevertheless, it is worth mastering some of the most important options and techniques early in one's Mathematica career, particularly for science and engineering applications for which visualization is an important tool for solving problems and developing insights.  In this notebook we introduce the plotting commands and options that I have found to be most useful for routine applications (at least in physics).

The following table lists selected built-in plotting functions with schematic syntax and brief descriptions.  In addition there are animation functions, such as MoviePlot, which we will not discuss here.  The behavior of each of these functions can be controlled by a vast array of plotting options — we cannot hope to illustrate all functions and options without exhausting the reader (and the writer)!  Plotting functions can also be combined with graphics primitives to add text, line drawings, or other visual information not usually described as a plot.  By using the Reference Guide or Help Browser you should be able to find a command suitable for practically any type of plot or figure that you might need and the use of the available options should, with a little practice, be almost self-explanatory.

({{Selected built - in plotting functions}, {({{function, purpose/format}, {Plot[y,{x,(Subscript[x, min]),(Subscript[x, max])}], simple plot of y[x] 
                        or list of functions}, {ListPlot[list], plot list of {x, y} points}, {ParametricPlot[{x, y}, {t, (Subscript[t, min]), (Subscript[t, max])}], parametric plot of y[t] vs .  x[t]}, {DensityPlot[f,{x,(Subscript[x, min]),(Subscript[x, max])},{y, (Subscript[y, min]), (Subscript[y, max])}], 2 - 
                        d grayscale or color density plot of f[x, y]}, {ContourPlot[f,{x,(Subscript[x, min]),(Subscript[x, max])},{y, (Subscript[y, min]), (Subscript[y, max])}], 2 - d  contour plot of f[x, y]}, {ListDensityPlot[list], \(density\ plot\ for\ 2×2\ array\ of\ values\)}, {ListContourPlot[list], \(contour\ plot\ for\ 2×2\ array\ of\ values\)}, {Plot3D[z,{x,(Subscript[x, min]),(Subscript[x, max])},{y, (Subscript[y, min]), (Subscript[y, max])}], 3 - 
                        d plot of z[x, y] or list of functions}, {ParametricPlot3D[{x, y, z}, {t, (Subscript[t, min]), 
                          (Subscript[t, max])}], parametric plot of {x[t], y[t] , z[t]}}, {ListPlot3D[list], plot list of {x, y, z} points}})}})

In addition to the built-in functions, there is also a large number of standard packages which either enhance the features of built-in functions or provide more specialized plotting formats.  We list some of the more useful packages in the table below, but if you do not find what you need here be sure to check the appropriate directories for other standard or extra packages or MathSource for user-written packages.  Each of these packages is located in the Graphics directory and includes that directory as a prefix to its name.  For example, to use ImplicitPlot one would need the command Needs["Graphics`ImplicitPlot`"] or to use Graphics the repetitive command Needs["Graphics`Graphics`"].

({{Selected Graphics Packages}, {({{package, purpose/format}, {Graphics, large collection of common 2 - d formats}, {Graphics3D, large collection of common 3 - d formats}, {ImplicitPlot, plot equations,  related to ParametricPlot}, {MultipleListPlot, several lists with varying formats}, {PlotField, vector,  gradient,  hamiltonian fields}, {Legend, fancy legend formats}, {ParametricPlot3D, enhances built - in function}, {ContourPlot3D, 3 - d contour plots}, {Shapes, 3 - d shapes and transformations}, {Polyhedra, create and manipulate polyhedra}})}})

The easiest way to ensure that the required graphics package is available when needed, while avoiding shadows, is to load the master package Graphics`Master`.  Recall that a master package creates symbols for all important functions in any of the packages in its directory.  These symbols initially carry the attribute Stub and are nonfunctioning, but when that symbol is invoked the associated package is loaded automatically.  Thus, it is not necessary to remember in which package a particular symbol is found or to load that package before using any of the  symbols in its jurisdiction.  Nor does this method consume resources unnecessarily.  Therefore, we employ this method in the initialization section below.

In this notebook we discuss some of the basic features common to many of the plotting functions and provide examples of some of the more common functions, but do not attempt to cover everything.

Initialization

ClearAll["Global`*"];
Off[General::spell,  General::spell1];
$TextStyle = {FontFamily -> "Times", 
          FontSize -> 12};

List all symbols with Plot in their name.

?*Plot*

Now load the master graphics package

Needs["Graphics`Master`"]

and see that many more symbols related to Plot are found.

?*Plot*

Many of these symbols are just stubs, but will be fleshed out as needed below.

Plotting a function of one variable

Basic syntax

The basic plotting function is, of course, Plot with syntax Plot[f,{x,xmin,xmax},opts] where f  is an explicit function of the independent variable x and where xmin and xmax represent the limits of the interval to be plotted.  For example, the following command plots the inverse hyperbolic cosine.  Note that we use a range x ≥ 1 where that function produces real values.

Plot[ ArcCosh[x],  {x, 1, 10}]

Notice that the Plot command produced two output cells.  The first contains the plot itself and is displayed on the monitor.  The second carries an output label and contains the relatively useless message ⁃Graphics⁃.  The purpose of this message is to report that Plot has produced a Graphics object.  If we had assigned that object a name, we could then apply suitable transformation or display functions to that graphics object.  We will do this with other plots shortly.  For the moment, it is sufficient to recognize that the output cell can be suppressed by terminating the plot command with a semi-colon.  The graphics object is still produced, but the annoying message is no longer printed.  The choice of suppressing or printing this message is, of course, a matter of personal taste — I almost always suppress it.

Plot ((x^3)/(Exp[x] + 1)) for positive x.

Plot a) BesselJ[5,x] and b) BesselJ[6,x] for a range in x that is symmetric around 0.

Function evaluation

It is critically important that the function to be plotted produces a real number when its variable is replaced by a numerical value.  If your function contains unevaluated parameters, it cannot be plotted.  Perhaps the most common error encountered using plotting commands is to leave some constant in symbolic form.

Plot[Cos[k x],  {x, -1, 1}];

In the example above, because we failed to specify the value of k the argument does not evaluate to a number.  Although Mathematica complains that the function is not a machine-size real number, it isn't even a definite number of any kind.  Nevertheless, Mathematica will plot whatever it can, useful or not.  In this case, it simply produces a set of axes with default ranges and increments because that is the only part of the command it can evaluate.  It is much happier with the versions below, in which the function is specified completely.

Plot[Cos[Pi x],  {x, -1, 1}];

k  =  Pi;
Plot[Cos[k x],  {x, -1, 1}];

Now that k has been set, it can be used freely.  However, we should remember to clear it if we ever want to use it as a symbol.

f[x_]  :=  x Cos[π x]

Plot[f[x],  {x, -1, 1}];

Now suppose that we create a function by assigned a name to a numerical solution of some differential equation.  [We will discuss the details of NDSolve later.]

g[x_]  :=  
      y[x] /. NDSolve[{(y^″)[x] == x Sin[x],  
            y[0] == 0,  (y^′)[0] == 1}, 
          y[x], {x, 0, 10}]

If we try to plot this function directly, we get several errors messages which arise because the function is not fully evaluated before we try to plot.  Similar messages are often encountered when the function argument supplied to Plot is actually a command rather than an explicit function.

Plot[g[x],  {x, 0, 5}];

The solution to this difficulty is to wrap our function inside the Evaluate function.  Evaluate instructs Mathematica to evaluate an expression and the commands it contains first before passing the contents as an argument for processing by another command.  Thus, if we evaluate g[x] first, the argument becomes a well-defined function which can be plotted directly.

Plot[Evaluate[g[x]],  {x, 0, 10}];

It is good practice to routinely wrap the evaluation function around the function we wish to plot.  It will do no harm for functions that don't need prior evaluation, and sometimes saves computation time, but will avoid many annoying messages.

Plotting function lists

The plot command can place several curves on the same graph if given a list of functions as its first argument.  A couple of simple examples follow.

Plot[{LaguerreL[1, x], LaguerreL[2, x], LaguerreL[3, x]},  {x, 0, 
          10}];

Plot[ 
        Evaluate[ Table[LegendreP[n, x], {n, 0, 10}]], {x, -1, 
          1}];

Useful embellishments

Options available to Plot

Although one often neglects to label plots properly while developing a solution to a problem, treating the notebook as glorified scratch paper, you should always label figures as the final solution is approached.  It may also be necessary to override the default choices for plotting range or resolution.  The options available to Plot are easily printed, and most are common to other similar plotting commands.

Options[Plot]

Axis labels and titles

The simplest labeling uses AxesLabel for the axes and PlotLabel for the entire figure.  One simply replaces the defaults by a list of strings for AxesLabel, where the first label is for the x-axis and the second for the y-axis, or by a single string for PlotLabel.

\(\(Plot[Gamma[x], {x, \(-5\), 5}, 
	
        AxesLabel -> {"x", \ "Γ[x]"}, \ 
        PlotLabel -> "Gamma Function"];\)\)

Unfortunately, Mathematica is not always terribly smart about where it places those labels.  Although we can place labels manually, I prefer to use Frame->True to draw a frame around the figure and FrameLabel->{bottom string, left string, top string, right string} to place labels outside the edges of the figure.  Note that FrameLabel expects lists with either 2 or 4 elements.  Thus, if we do not want to label the right side we can include a blank string with the 3 labels we do want, or we can give 2 labels to FrameLabel and use PlotLabel for the top.

Plot[Gamma[x], {x, -5, 5},  Frame -> True, 
      FrameLabel -> {"x",  "Γ[x]", "Gamma \
Function", " "}]

Plot[Gamma[x], {x, -5, 5},  Frame -> True, 
        FrameLabel -> {"x",  "Γ[x]"},  
        PlotLabel -> "Gamma Function"];

Grid lines

It is often nice to add grid lines for ease in reading values.  The simplest method uses GridLines->Automatic, although it is possible to more sophisticated options.

Plot[Gamma[x], {x, -5, 5},  GridLines -> Automatic, 
        Frame -> True,  
        FrameLabel -> {"x",  "Γ[x]"},  
        PlotLabel -> "Gamma Function"];

Plot range

The default plot ranges may not be suitable for functions which vary strongly over parts of their domain.  For example, if there is a singularity, the default choices may emphasize the divergence while you would prefer to see the behavior for smaller values found away from the singularity.

Plot[Tan[x],  {x, -π,  π}];

The PlotRange option can be used to adjust these ranges.  If we replace the default with a list of the form {{xmin,xmax},{ymin,ymax}} we can limit the plot to specified ranges.

Plot[Tan[x],  {x, -π,  π}, 
        PlotRange -> {Automatic, {-5, 5}}];

Note that we can replace either of the range specifications by All, which includes all points, or Automatic, which drops outlying points.  For a two-dimensional plot we could have given the y-range only because the x-range was already supplied by the second argument to Plot.  Similarly, for a three-dimensional plot a single range would be applied to the z-axis.  However, if more than one range is given, the all ranges (2 or 3) must be given.

tanPlot  = 
        Plot[Tan[x],  {x, -π,  π}, 
          PlotRange -> {-5, 5}];

Resolution and smoothness options

Obviously Mathematica must evaluate the function for a finite number of points if it is to generate a plot.  According to the options listed above, the default value of PlotPoints is 25 for its initial evaluation.  Because Mathematica uses an adaptive sampling algorithm, this parameter represents the minimum number of points.  If a strong kink is detected, it may automatically increase the density of points in that region in an attempt to improve the resolution of the plot.  However, sometimes a kink will not be noticed and we might get a somewhat spurious result, or perhaps we are fussy about segmented lines.  In either case, we can increase PlotPoints to improve either the accuracy or appearance of the plot.  Other relevant parameters are MaxBend, which is the maximum angle permitted between successive line segments, and PlotDivision, the maximum number of bisections permitted to reduce the bend angle.  These parameters are obviously interrelated.

For example, a smoother plot of the tangent function can be obtained by reducing MaxBend from its default value of 10.  Even so, a purist might object to the vertical lines connecting ±∞.

Plot[Tan[x],  {x, -π,  π}, 
        PlotRange -> {-5, 5}, MaxBend -> 1];

This technique will usually work for most "normal" functions, but may not be sufficient for highly oscillatory functions or functions which resemble pulse trains.  Here, for example, is a function for which the unguided sampling algorithm fails miserably.

Plot[(1 + Tanh[(x^2) Sin[2  x]])/2, {x, 0, 100}];

With a larger number value of PlotPoints the periodic behavior of this function is revealed.  Except perhaps for the first pulse, this function provides a reasonable analytic facsimile of a train of unit pulses.

Plot[(1 + Tanh[(x^2) Sin[2  x]])/2, {x, 0, 100}, 
        PlotPoints -> 100];

Although our pulse train may appear to be a rather artificial example, you will undoubtedly soon encounter some peculiar kinks that are often merely artifacts of the sampling algorithm and which disappear upon closer examination.

Locating the points

A graphics object contains a list of the points that uses to draw curves.  Examination of the placement of those points should offer some insight into the adaptive sampling algorithm.  Examining the full form of a graphics object,

FullForm[tanPlot]

we find that the data are contained within a nested structure of the form List[List[Line[List[pt1,pt2,⋯]]]] where each point is itself a list containing its coordinates.  The points can be extracted by peeling off 4 layers to produce a list of the underlying points.  Each layer is peeled by successive applications of First; hence, First must be nested 4 times using Nest.

getPoints[graphics_]  :=  Nest[First, graphics, 4]

tanPoints  =  getPoints[tanPlot];

ListPlot[tanPoints, PlotRange -> {-10, 10}];

Clearly the points are spaced more densely where the curvature is large.

Aspect ratio

The appearance of a plotted curves depends upon the length units employed for the axes.  Although these units often do not affect one's appreciation of the curve, it is sometimes necessary to control the aspect ratio between horizontal and vertical length units.  Consider, for example, a unit circle expressed as two branches of a square-root function.

Plot[{(Sqrt[1 - (x^2)]), -(Sqrt[1 - (x^2)])}, {x, -1, 
          1}];

With default options the circle appears deformed into an ellipse.  A more accurate impression is obtained by choosing AspectRatio->1.

Plot[{(Sqrt[1 - (x^2)]), -(Sqrt[1 - (x^2)])}, {x, -1, 1}, 
        AspectRatio -> 1];

Some nerd decided that aesthetically pleasing figures would be generated using a default aspect ratio equal to the reciprocal of the so-called golden ratio, and some choice had to be made, but you should not feel obligated to share his/her sensibilities!

?GoldenRatio

Line styles

When plotting several curves together, it is often useful to distinguish them either by dashing pattern, color, or thickness and options are provided to control any of these attributes.  Your choices should be bundled together in the replacement list for the PlotStyle option.  The basic syntax is PlotStyle->{style} or PlotStyle->{{style1},{style2},...} where each {style} is a list of graphics directives, including Dashing, RGBColor, Hue, Thickness, among others.  If a figure contains many lines, the styles are applied cyclically.  Because style specifications tend to be verbose and may be used for several related figures, it is convenient to collect them into list symbols.  Several examples follow.

line[1]  =  {Dashing[{0.02, 0.02}],  RGBColor[1, 0, 0],  
          Thickness[0.01]};
line[2]  =  {Dashing[{0.02, 0.02}],  RGBColor[0, 1, 0],  
          Thickness[0.01]};
line[3]  =  {Dashing[{0.02, 0.02}],  RGBColor[0, 0, 1],  
          Thickness[0.01]};

lines  =  Table[line[n], {n, 3}];

Plot[ Evaluate[ Table[LegendreP[n, x], {n, 0, 4}]], {x, -1, 1}, 
        PlotStyle -> lines];

Here we provide very brief explanations of these graphics directives; please refer to the Mathematica Book or to the Help Browser for more detailed information about these or related directives.

Thickness[r] specifies line thickness as a fraction r of the width of the entire plot

AbsoluteThickness[d] specifies line thickness in units of printer's points ( ≈  (1/72)inch)

Dashing[ {(Subscript[r, 1]),  (Subscript[r, 2]),  ...} ] specifies a sequence of segments and spaces as sizes relative to figure width

AbsoluteDashing[ {(Subscript[r, 1]),  (Subscript[r, 2]),  ...} ] specifies a sequence of segments and spaces in units of printer's points ( ≈  (1/72)inch)

RGBColor[r,g,b] specifies color values between 0 and 1 for red, green, and blue

Hue[h] specifies hue values between 0 and 1

Text styles

The font and style parameters used to format text and labels can be chosen by replacing the default TextStyle.  The default value is $TextStyle and depends upon installation, but is usually empty.  However, I usually prefer to use somewhat larger labels than produced by the default settings and usually include the following statement near the beginning of my notebooks.  Then, providing that the cells are executed in order, one should find a slightly improved version of an earlier plot.

$TextStyle = {FontFamily -> "Times", 
          FontSize -> 12};

Now we define a plot for the gamma function and play with TextStyle a little.

plotGamma  :=  
        Plot[Gamma[x], {x, -5, 5},  GridLines -> Automatic, 
          Frame -> True,  
          FrameLabel -> {"x",  "Γ[x]"},  
          PlotLabel -> "Gamma Function"];

$TextStyle = {FontFamily -> "Courier", 
          FontSize -> 12};

plotGamma;

Among the options available to TextStyle are:

FontFamily — type of font to apply.  Common choices are "Courier", "Times", and "Helvetica".  More specific font names can be given also, with blanks replaced by dashes, such as "Times-New-Roman".

FontWeight — "Plain", "Bold", or "ExtraBold"

FontSlant — "Plain" or "Italic"

FontSize — in printer's points

FontColor — specified using GreyLevel,  RBGColor , CMYKColor, or Hue

Background — specified using GreyLevel, RGBColor, CMYKColor, or Hue

$TextStyle = {FontFamily -> "Courier", 
          FontSize -> 16,  FontSlant -> "Italic",  
          FontWeight -> "Bold"};

plotGamma;

$TextStyle = {FontFamily -> "Times", 
          FontSize -> 12};

Rather than reset the default $TextStyle globally, it is often preferred to modify this variable locally instead.  This can be done easily using Block but, as previously noted in functions.nb, does not work in Module or With.  Of course, one can still embed a Module or With statement within Block.  We use Block to temporarily modify system variables or defaults.

Verify that the following statement does not affect the default value for $TextStyle or the appearance of other plots.

Block[{$TextStyle = {FontFamily -> "Times", 
              FontSize -> 16, FontSlant -> "Italic",  
              FontWeight -> "Bold", 
              FontColor -> RGBColor[0, 1, 0]}}, 
        Plot[Gamma[x], {x, -5, 5},  GridLines -> Automatic, 
          Frame -> True,  
          FrameLabel -> {"x",  "Γ[x]"},  
          PlotLabel -> "Gamma Function"]];

Alternatively, you can use StyleForm[string, options] to select the formatting options for any text string.

xlabel = 
      StyleForm["x", FontFamily -> "Times", FontSize -> 12, 
        FontSlant -> "Italic",  FontWeight -> "Bold", 
        FontColor -> RGBColor[0, 1, 0]]; 
    ylabel = StyleForm["Γ[x]", 
        FontFamily -> "Times", FontSize -> 16, 
        FontSlant -> "Italic",  FontWeight -> "Bold", 
        FontColor -> RGBColor[1, 0, 0]]; 
    plotLabel = 
      StyleForm["Gamma Function", 
        FontFamily -> "Lucida-Calligraphy", FontSize -> 18, 
        FontSlant -> "Italic",  FontWeight -> "Bold", 
        FontColor -> RGBColor[0, 0.5, 0.5]];

These formatted strings can be printed

Print[xlabel, "    ", ylabel, "    ", plotLabel]

or used to label plots.

Plot[Gamma[x], {x, -5, 5},  GridLines -> Automatic, 
        Frame -> True, FrameLabel -> {xlabel,  ylabel},  
        PlotLabel -> plotLabel];

Reading values from a plot

Suppose that you need to solve a transcendental equation.  FindRoot requires that you specify a starting value or the region in which to look, or perhaps you would be satisfied with a visual solution.  In either case, you can use the mouse to read values from a plot.

For example, consider the equation (ξ/(Sqrt[(β^2) - (ξ^2)]))  ==  
        Cot[ξ] which arises in the eigenvalue problem for the square well.  Where should solutions be sought?  First, plot the two sides separately for some value of β, obviously limiting the range to ξ ≤ β.

lhs  =  (ξ/(Sqrt[(β^2) -  (ξ^2)]));   rhs  =  
      Cot[ξ];

Plot[Evaluate[{lhs, rhs} /. β -> 5],  {ξ, 0,  5}, 
        PlotRange -> {Automatic, {0, 5}}];

The vertical line represents the divergence of the cotangent function at π and should be disregarded, while the other two intersections are the desired solutions.  If you now click on the figure you will see a bounding box.  The size of the figure can be changed by grabbing one of the buttons and dragging the border with the mouse.  More importantly for us, the cursor appears as a cross-hair which can be placed over the point of interest.  To read values from the graph follow these steps.

First press and hold the control key.  If you then move the mouse you should see the cursor coordinates somewhere in the border of the notebook display (lower left for me).

Clicking on the desired point, while the control key is held, then places a point on the figure.

Next, the editor copy function (Ctrl-C) copies the coordinates of that point into the paste buffer.

Finally, clicking somewhere else in the notebook and using the paste editing function (Ctrl-V) pastes those coordinates into the notebook.

The approximate solutions that I found in this manner are listed below.

{1.3035,  0.325631};  {3.82772,  1.24741};

More precise values are now obtained easily.

eq  =  (lhs == rhs) /. β -> 5;

FindRoot[eq, {ξ, 1.3}]

FindRoot[eq, {ξ, 3.8}]

Graphically find the first three solutions to the equation Sin[x] == Log[(x/(x - 1))]; then find more precise numerical solutions.

Manipulating graphics objects

Disabling or enabling display

Plots are created as graphics objects, which can be named or placed into lists or arrays for further processing.  For example, one often collects several figures into a graphics array to produce a combined display.  These figures could be superimposed or could be displayed as a matrix of separate figures.  It is then useful to suppress display of intermediate results.  This can be done by using the option DisplayFunction whose default value $DisplayFunction generally instructs Mathematica to display graphical output on a video monitor.  If one chooses $DisplayFunction->Identity as one of the plot options, the identity function does not produce a display.  One can then display the graphics object later using Show.

For example, suppose that we create several plots with disabled display.

\(\(\(\(Clear[x, v, a, t];\)

    x[t]\  = \ Cos[t]; \ v[t]\  = \ D[x[t], t]; \ a[t]\  = \ D[v[t], t];

    \(plot[x]\  = \ 
        Plot[Evaluate[x[t]], {t, 0, 2  π}, 
          DisplayFunction -> Identity];\)\ 

    \(plot[v]\  = \ 
        Plot[Evaluate[v[t]], {t, 0, 2  π}, 
          DisplayFunction -> Identity];\)\ 

    \(plot[a]\  = \ 
        Plot[Evaluate[a[t]], {t, 0, 2  π}, 
          DisplayFunction -> Identity];\)\)\(\ \)\)\)

Any one of these can be displayed using Show, but we need to reset the display function.

Show[plot[v], DisplayFunction -> $DisplayFunction];

Superimposing graphics objects

One can superimpose several graphics objects by supplying Show with a list.  If DisplayFunction->Identity was used in one or more of the graphics objects input, we need to reset DisplayFunction->$DisplayFunction. Note that the options chosen for the first plot in the list prevail.  Unfortunately, there is no simple way to change PlotStyle for various elements of the list.

Show[{plot[x], plot[v], plot[a]}, 
        DisplayFunction -> $DisplayFunction];

An alternative method for superimposing plots which does not require manipulation of DisplayFunction is provided by the function DisplayTogether found in the Graphics`Graphics` package.  In the example below, only the final plot is displayed.

\(\(\(\(Clear[x, v, a, t];\)

    x[t]\  = \ Cos[t]; \ v[t]\  = \ D[x[t], t]; \ a[t]\  = \ D[v[t], t];

    \(DisplayTogether[Plot[Evaluate[x[t]], {t, 0, 2  π}], 
        Plot[Evaluate[v[t]], {t, 0, 2  π}], 
        Plot[Evaluate[a[t]], {t, 0, 2  π}], Frame -> True, 
        FrameLabel -> {"time", "x,v,a"}, \ 
        PlotLabel -> "simple harmonic motion"];\)\)\(\ \)\)\)

DisplayTogether also accepts the formatting options recognized by Show.

Recreate the figure above using Show instead of DisplayTogether.  Note that without manipulating DisplayFunction, Show produces intermediate plots that you probably do not want.

Creating a graphics array

A graphics array is created using GraphicsArray[list] where the argument is either a 1-dimensional or 2-dimensional list.  Because GraphicsArray comes with its own default DisplayFunction option, Show will then display the plot without resetting the display function.  Note that even if the list contains only one element, it must still include curly braces so that it is recognized as having the correct type.

Show[GraphicsArray[{plot[x]}]];

A 1-dimensional list is displayed as a row.

Show[GraphicsArray[{plot[x], plot[v], plot[a]}]];

A 2-dimensional array is displayed as a rectangular matrix.  Below is a degenerate 2-dimensional list that generates column output.

Show[GraphicsArray[{{plot[x]}, {plot[v]}, {plot[a]}}]];

One can also use DisplayTogetherArray instead of GraphicsArray to avoid manipulating DisplayFunction.  This function is found in Graphics`Graphics`.

Reproduce one of the arrays above using DisplayTogetherArray.

Creating plotting functions

Often we will wish to use similar commands to plot a function for several choices of its parameters, perhaps over different ranges, or with other minor variations of the options.  Rather than reproduce the necessary command with cut-and-paste and edit the copies, it is better to define commands which perform plots on demand, given the necessary parameters.

For example, one can show that modified Bessel functions have the asymptotic behavior (Subscript[I, n])[z]~Exp[z]/(Sqrt[2  πz]) (1  +  
            O( (1/z))).  The commands below define and illustrate a function that can be used to display  the approach to asymptopia.  The arguments of plotAsymptoticBesselI are the order, the minimum and maximum arguments to display, and a set of options.  Note that the triple underscore indicates that zero or more arguments collectively named opts may be included.  Of course, we can omit optional parameters altogether.

plotAsymptoticBesselI[n_, xmin_, xmax_, opts___]  := 
      Plot[Evaluate[(Sqrt[2  π x]) Exp[-x] BesselI[n, x]], {x, xmin, 
          xmax}, opts]

plotAsymptoticBesselI[2, 0, 50];

tableAsymptoticBesselI  =  
        Table[plotAsymptoticBesselI[n, 0, 50, 
            DisplayFunction -> Identity], {n, 0, 5}];

Show[tableAsymptoticBesselI, 
        DisplayFunction -> $DisplayFunction];

Plotting points

Basic list plots

Not surprisingly, a list of points can be plotted using ListPlot for two dimensions or ListPlot3D for three dimensions.  Suppose that we generate a list of points that might resemble data for some reaction.

bw[x_, 
        x0_, Γ_] := ((((Γ/2))^2)/((((x - x0))^2) +  (((Γ/2))^2)))

bwData2  = 
        Table[{x,  bw[x, 1, (1/2)] (0.8 + 0.4 Random[])}, {x, 0, 3, 
            0.1}];

The options for ListPlot are the same as those for Plot.  The appearance of the points can be adjusted using PlotStyle, with the most important adjustment being the point size — the defaults size is too small on most monitors.

plot2[bwData2]  = 
        ListPlot[bwData2, 
          PlotStyle -> AbsolutePointSize[4]];

It is useful to superimpose the theoretical curve as well.

plot[bwCurve]  =  
        Plot[bw[x, 1, (1/2)], {x, 0, 3}, 
          DisplayFunction -> Identity];

Show[{plot2[bwData2], plot[bwCurve]},  
        DisplayFunction -> $DisplayFunction];

If we were fitting data, we would probably want to generate figures similar to the one above except that we would also want to include error bars.  For this we need to load a package that extends the number of plotting commands available.  In particular, this package includes ErrorListPlot which plots a list of points of the form {(Subscript[x, i]),(Subscript[y, i]),(Subscript[dy, i])}.

bwData3  = 
        Table[{x,  bw[x, 1, (1/2)] (0.8 + 0.4 Random[]), 
            0.1 bw[x, 1, (1/2)]}, {x, 0, 3, 0.1}];

Show[{ErrorListPlot[bwData3, DisplayFunction -> Identity], 
          plot[bwCurve]}, 
        DisplayFunction -> $DisplayFunction];

However, you should note that this example is intended to illustrate some of the capabilities of ListPlot and ErrorListPlot and does not accurately represent the statistical properties of a fit.  Data of this type would probably be distributed according to either a Poisson or Gaussian distribution and the error bars should be derived from the variances of the appropriate distribution.  Data analysis will be discussed later in the course.

Fancier list plots using MultipleListPlot

MultipleListPlot[dataset1,dataset2,⋯, options] can be used to plot several lists together, giving each a different symbol and/or line, and can display error bars in vertical and/or horizontal directions.  This function is contained in a package by the same name, but has already become available by loading the master graphics package.  Each data set should have the form {{point,error},⋯} where point is an {x,y} pair and error is an ErrorBar object of the form ErrorBar[yerr] or ErrorBar[xerr,yerr].  Each error is either a single value representing a symmetric uncertainty or an interval about zero of the form {negerr,poserr} which can be used for asymmetric error bars.

The options for MultipleListPlot include:

SymbolShape->{primitives} — gives list symbol shapes to be assigned cyclically to data sets

SymbolStyle->{directives} — describes color and other style options

SymbolLabel->{labels} — cyclic list of labels

ErrorBarFunction->function used to create a graphics object representing the error bar

The most important options apply to shape and style.  The shape can be specified using PlotSymbol[shape,size, options] where size is optional and where the available shapes include Diamond, Triangle, Star, Box, and others.  The only option presently available for these shapes is Filled, which defaults to True.  Alternatively, MakeSymbol can be used to create other shapes.

Although there are too many options and features to cover here, an example should illustrate some of the features of this function.  Below we create two data sets with random fluctuations based upon the same basic shape but with different error bars, here taken to be symmetric.  The two sets are plotted with different symbol formats to illustrate the most important features of MultipleListPlot.

Clear[bwData];
bwData[x0_, Γ_, δx_, δy_, xmin_, xmax_, 
        xinc_] := Table[{x,  bw[x, x0, Γ]}, {x, xmin, xmax, 
            xinc}]  /. {{x_, 
              y_} :> {{x, 
                y Random[Real, {1 - δy, 1 + δy}]}, 
              ErrorBar[δx, (Sqrt[1/3]) y δy]}}

set1 = bwData[1, (1/2), 0.1, 0.1, 0, 3, 0.2];
set2 = bwData[1, (1/2), 0.05, 0.2, 0.1, 3, 0.2];

DisplayTogether[
        MultipleListPlot[set1, set2, 
          SymbolShape -> {PlotSymbol[Triangle, 5], 
              PlotSymbol[Diamond, 5, Filled -> False]}, 
          SymbolStyle -> {RGBColor[0, 1, 0], RGBColor[1, 0, 0]}], 
        Plot[bw[x, 1, (1/2)], {x, 0, 3}]];

Unfortunately, there do not appear to be versions adapted for semi-log or log-log formats yet.

Specialized two-dimensional plots

Often one requires more specialized plotting formats.  The standard package Graphics`Graphics` provides many of the more common plotting formats with syntax and options very similar to Plot.  In addition, there are several variations of BarChart and PieChart and variations of ListPlot which plot labelled points or use text as points.  The most useful of these functions are summarized in the table below and others can be found in the Help Browser.

({{Selected functions in Graphics`Graphics`}, {({{function, purpose/format}, {LogPlot[y,{x,(Subscript[x, min]),(Subscript[x, max])}], log y vs .  linear x for function}, {LogLinearPlot[y,{x,(Subscript[x, min]),(Subscript[x, max])}], linear y vs. log x}, {LogLogPlot[y,{x,(Subscript[x, min]),(Subscript[x, max])}], log y vs .  log x}, {LogListPlot[{{x, y},  ... }], log y vs .  
                        linear x for list of points}, {LogLinearListPlot[{{x, y},  ... }], linear y vs. log x}, {LogLogListPlot[{{x, y},  ... }], log y vs .  log x}, {PolarPlot[r,{θ,(Subscript[θ, min]),(Subscript[θ, max])}], polar plot of r[θ]}, {ErrorListPlot[{{x, y, δy},  ... }], points ((Subscript[x, i]),(Subscript[y, i])±(Subscript[δy, i])) with error bars}, {BarChart[list], bar charts or histograms}, {PieChart[list], pie charts}, {PlotVectorField[{(Subscript[f, x]),(Subscript[f, y])},{x, (Subscript[x, min]), (Subscript[x, max])},{y, (Subscript[y, min]), (Subscript[y, max])}], 2 - d vector function}, {ListPlotVectorField[{{x, y, f[x, y]},  ... }], 2 - d vector list}, {\(SphericalPlot3D[
                      r, {θ, θ\_min, θ\_max}, {ϕ, ϕ\_min, ϕ\_max}]\), spherical plot of r[θ, ϕ]}})}})

If your data or function covers a very wide dynamic range, as might be expected from an exponential function, a semilog plot will probably be more useful than a linear plot, as simulated below.

DisplayTogether[
        LogPlot[(x^2) Exp[-(x^2)], {x, 0, 5}, 
          PlotRange -> {{0.001, 5}, Automatic}, 
          GridLines -> Automatic], 
        LogListPlot[
          Table[{x, (x^2) Exp[-(x^2)] Random[Real, {0.9, 1.1}]}, {x, 
              0.1, 4, 0.05}], 
          PlotStyle -> {AbsolutePointSize[4]}]];

If you suspect that your data follow a power-law function, y ∝ (x^α), a log-log plot should display a straight line, as simulated below.

DisplayTogether[
        LogLogPlot[(x^(-1/3)), {x, 0, 5}, GridLines -> Automatic], 
        LogLogListPlot[
          Table[{x, (x^(-1/3)) Random[Real, {0.9, 1.1}]}, {x, 0.1, 4, 
              0.02}], PlotStyle -> {AbsolutePointSize[
                4]}]];

Use PolarPlot to produce the following curves: 
a) four-leaved rose, r = (cos^2) θ - (sin^2) θ;  
b) cardioid, r  =  1  +  sin θ; 
c) limaçon, r = (1/2) +  cosθ.

Plotting a function of two variables

Plot3D

An explicit function of two independent variables can be displayed using Plot3D.  The basic syntax is Plot3D[f,{x,xmin,xmax},{y,ymin,ymax}].  Note that the default sampling is 15 points in each directions, which is often not sufficient.

\(\(Plot3D[
        Evaluate[Re[SphericalHarmonicY[3, 1, θ, ϕ]]], {θ, 
          0, π}, {ϕ, 0, 2  π}, PlotPoints -> 50, 
        PlotRange -> {\(-1\), 1}, 
        AxesLabel -> {"θ", "ϕ", \*""Re[(Subscript[Y, λ])m]""}];\)\)

In addition to the options available to Plot, Plot3D comes with options to control the shading scheme and the viewpoint.  An example using the ViewPoint option is given below.  Note that these values were obtain by using the 3D ViewPoint Selector from the Input menu.  Alternatively, there is a shortcut key for those who remember such things easily.

To change the viewpoint follow these steps:

if no ViewPoint data are present in the plot command, click at an appropriate insertion point near the end of the argument sequence to indicate where the ViewPoint data should be inserted

if there are pre-existing viewpoint data , highlight those data with the cursor to replace old data with new data

activate the selector using Input ↦ 3DViewPoint Selector or the corresponding shortcut

use the control bars to vary to taste

click Paste.  This should insert or replace the viewpoint data.

replot to see the result.  Note that values that are out of range are clipped.  Of course, you can vary the PlotRange also.

Plot3D[
        Evaluate[Re[Gamma[x  +  I y]]], {x, -5, 5}, {y, -5, 5}, 
        PlotPoints -> 50, 
        ViewPoint -> {-5.009,  -6.671,  1.524}];

Copy the input cell above and practice varying the ViewPoint by modifying your copy.

Parametric plots

Two-dimensional parametric functions

Many functions are expressed parametrically.  Two variables connected by a single parameter can be plotted against each other using ParametricPlot.  The basic syntax is ParametricPlot[{x[t],y[t]},{t,tmin,tmax}] with the usual options.  In the following example we define a plotting function with options, create a table of parametric plots, and display a graphics array.  Of course, you will probably apply similar techniques to problems more interesting than Lissajous figures!

lissajous[n_, ϕ_]  :=  {Cos[t], 
        Sin[n t  +  ϕ]}

plotLissajous[n_, ϕ_, opts___]  :=  
      ParametricPlot[Evaluate[lissajous[n, ϕ]], {t, 0, 2  π}, 
        opts]

lissajousTable  =  
        Table[plotLissajous[n, ϕ, AspectRatio -> 1, 
            Axes -> False, DisplayFunction -> Identity], {n, 1, 
            4}, {ϕ, 0, π, (π/4)}];
Show[GraphicsArray[lissajousTable]];

Plot the curve described by the parametric equations

\(TraditionalForm
    \`x = \(r\ \((1 - sin(t))\)\ \ \ \ \ \ \ \ \ \ \ y = 
        r\ \((1 - cos(t))\)\)\)

for the interval {t,-2π,2π}.

ImplicitPlot

The function ImplicitPlot, found in a package by the same name, plots the solution to an equation and is closely related to ParametricPlot.  Thus, ImplicitPlot[f[x,y]==g[x,y], {x,xmin,xmax}] uses Solve to obtain a solution of the form y[x] and plots the result over the specified range of x.  Implicit contour plots and methods for avoiding singularities are also available; further detail can be obtained from Help when needed.

ImplicitPlot[(y^2) -  (x^2)  ==  1,  {x, 5, -5}, 
        PlotPoints -> 50,  ImageSize -> 144];

Notice that both branches are obtained automatically.  ImplicitPlot will also accept a list of equations.

Plot the real solutions to the lemniscate equation, (((((x^2) + (y^2))))^(2 ))= (x^2) - (y^2).

Three-dimensional parametric functions

A three-dimensional trajectory expressed in terms of three coordinate functions {x[t],y[t],z[t]} connected by a single parameter t can be displayed using ParametricPlot3D with basic syntax 
ParametricPlot3D[{x[t],y[t],z[t]}, {t,tmin,tmax}].

For example, a charged particle in a uniform magnetic field follows a helical trajectory which can be parametrized and displayed as follows.  For simplicity we have chosen the magnetic field along the z-axis and have chosen an arbitrary ratio between angular and linear velocities.  In order to display just the shape, the box and axes have been suppressed.

path = {Cos[5  t], Sin[5  t], t};
ParametricPlot3D[Evaluate[path], {t, 0, 10}, Boxed -> False, 
        Axes -> False, AspectRatio -> Automatic];

SphericalPlot3D

The package Graphics`ParametricPlot3D` provides extensions to the built-in version of ParametricPlot3D.  Among these is a function SphericalPlot3D which displays f[θ, ϕ] as a parametric function of polar angle, θ, and azimuthal angle, ϕ, by interpreting the function as the radial coordinate.  Because the radius must be positive, one often wraps the target function within Abs.

For example, below we create functions which plot individual spherical harmonics and then assemble a graphics array for {m,0,λ}.

plotYlm[λ_, m_]  := 
      SphericalPlot3D[ 
        Evaluate[
          Abs[SphericalHarmonicY[λ, 
              m, θ, ϕ]]], {θ, 0, π}, {ϕ, 0, 
          2  π}, Boxed -> False, Axes -> False, 
        DisplayFunction -> Identity]

tablePlotYlm[λ_]  :=  
      Table[plotYlm[λ, m], {m, 0, λ}]

Show[GraphicsArray[tablePlotYlm[2]]];

Contour plots

Contour or density plots often prove very useful in locating extrema, ridges, or other important features of functions of two or more dimensions.  These plots can also help in finding starting points for numerical solution of equations.

The basic syntax is
	DensityPlot[f[x,y], {x,xmin,xmax},{y,ymin,ymax}]	or
	ContourPlot[f[x,y], {x,xmin,xmax},{y,ymin,ymax}]

Common options include PlotPoints to increase the resolution of the figure or ColorFunction to apply a coloration function based upon the values of the function.  For ContourPlot the option Contours->n specifies that n equally spaced contours or Contours->list specifies particular contours in the form of a list.

Evaluate the following cells to compare density and contour plots of a simple function.

DensityPlot[
        Exp[-((x^2) + (y^2))/20] Cos[x y], {x, -4, 4}, {y, -4, 
          4}, PlotPoints -> 100, 
        ColorFunction -> Hue];

ContourPlot[
        Exp[-((x^2) + (y^2))/20] Cos[x y], {x, -4, 4}, {y, -4, 
          4}, Contours -> 25, PlotPoints -> 100, 
        ColorFunction -> Hue];

You can also use ContourPlot to find starting values for numerical solutions of simultaneous equations.  For example, suppose you wish to solve the following system of equations.

eqs = {(x^3) (y^3) == 
            2, (( x y)/8) + ((((x/2)))^2)  +  ((((y/3)))^2) == 
            2};

If convert these equations to a pair of expressions which should both have the value zero

expressions = eqs /. Equal -> Subtract

and then superimpose contour plots for each that only show the special contour Contours->{0}

DisplayTogether[
        ContourPlot[
          expressions[[1]], {x, -5, 
            5}, {y, -5, 5}, Contours -> {0}, PlotPoints -> 50, 
          ContourShading -> False, 
          ContourStyle -> Dashing[{0.02, 0.01}]], 
        ContourPlot[
          expressions[[2]], {x, -5, 
            5}, {y, -5, 5}, Contours -> {0}, PlotPoints -> 50, 
          ContourShading -> False], 
        AspectRatio -> Automatic];

each of the intersections provides a solution.  By visual inspection or by using the cursor, we can now find approximate values to supply FindRoot as starting conditions.

Plots of this type can also be made for data in the form of lists using ListDensityPlot or ListContourPlot.  Three-dimensional contour plots can be made using ContourPlot3D or ListContourPlot3D in the Graphics`ContourPlot3D` package.

Creating a legend

Using the Legend package

The simplest method for adding a legend to a figure is to use the Graphics`Legend` package.  The option PlotLegend->{text1,text2,⋯} initiates the legend and assigns text to each line style cyclically.  The appearance of the legend can then be modified using LegendPosition, LegendSize, and other options.  The position and size variables are supposed to use the longest plot dimensions and scale that dimension to be in the range {-1,1} with 0 at the center.  An example is provided below and more examples and options can be found in the Help Browser.

\(\(labelJ = 
        StyleForm[\*""\!\(J\_2\)"", FontFamily -> "Helvetica", 
          FontColor -> RGBColor[1, 0, 0], 
          FontSize -> 12];\)\)
\(\(labelY = 
        StyleForm[\*""\!\(Y\_2\)"", FontFamily -> "Helvetica", 
          FontColor -> RGBColor[0, 1, 0], 
          FontSize -> 12];\)\)
labelLegend = 
        StyleForm["Bessel   functions", 
          FontFamily -> "Helvetica", 
          FontColor -> RGBColor[0, 1, 0], 
          FontSize -> 12];

Plot[Evaluate[{BesselJ[2, x], BesselY[2, x]}], {x, 0, 20}, 
        PlotStyle -> {{RGBColor[1, 0, 0]}, {Dashing[{0.02, 0.02}], 
              RGBColor[0, 1, 0]}}, PlotLegend -> {labelJ, labelY}, 
        LegendPosition -> {1, 0}, LegendSize -> {1. , 0.5}, 
        LegendLabel -> labelLegend];

However, the actual behavior of the position and size options is problematical and much trial-and-error may be required to achieve the desired placement.  Furthermore, Legend interferes with AspectRatio; using both together can have unpredictable results.  We also find that nonalphanumeric characters in legend text, including spaces, are sometimes rendered poorly.  Although this package appears promising, it's implementation in Version 3.0 leaves much to be desired and we hope that this feature will be friendlier in the next release.

Using graphics primitives

Another method, which is more cumbersome but more reliable, is to add text using graphics primitives.  The graphics primitive Text[expression,position] prints expression at a position specified as {x,y} in the units of the plot.  By default, position specifies the lower left corner but other choices and offsets can be chosen by including appropriate options.  The expression can be a string or text formatted using StyleForm.  A graphics object based upon a graphics primitive, such as Text, is created using Graphics[primitive] where in this case primitive stands for the output of Text.  Graphics can also accept a list of primitives.

The example below places labelJ and labelY, defined in the preceding section using StyleForm, as locations near the associated curves.  DisplayTogether is used to combine the basic plot with the graphics objects that represent the labels.  One could include arrows or other graphics objects also.

DisplayTogether[
        Plot[Evaluate[{BesselJ[2, x], BesselY[2, x]}], {x, 0, 20}, 
          PlotStyle -> {{RGBColor[1, 0, 0]}, {Dashing[{0.02, 0.02}], 
                RGBColor[0, 1, 0]}}], 
        Graphics[{Text[labelJ,  {2.5, 0.6}], 
            Text[labelY,  {2.5, -0.8}]}]];

Drawing with primitives

Primitives

Relatively simple illustrations can often be very helpful in clarifying a discussion.  Although Mathematica does not provide drawing tools, simple illustrations can be made fairly easily using graphics primitives.  A list of basic primitives for drawing lines, points, circle, polygons, text and other simple graphics is found at Graphics.  Packages, such as Arrow, Shapes, and Polyhedra, expand the selection of primitives.

Here we offer a couple of simple examples, but do not attempt to cover drawing techniques in much depth.

Example: labelled triangle

One of the exercises at the end of getting started .nb asked for a derivation of Heron's formula for the area of a triangle in terms of the lengths of its three sides using basic geometry and trigonometry.  The code below draws and labels a triangle.  Module is used to isolate the internal coordinates, which are explained by embedded comments.  Notice that we use symbolic coordinates in Line and Text functions computed using simple relationships between a few basic vertices rather than employ numerical values in these functions; in that way the integrity of the figure can be maintained easily if we later decide to alter some of the details of its shape.  Also notice that because the figure can be resized easily, we place an important vertex at {0,0} and choose one important length, here the base, to have unit length and express all other lengths relative to that base.  The best positions for text elements depend somewhat upon the final size of the figure and require some tweaking, but do not take long to adjust.  Finally, although not really needed, we included graphics directives and options to modify the appearance of some elements of the figure.

\(\(Module[
	
	 (*\ 
		a\  = \ 
            lower - left\ corner, \ 
		b\  = \ 
            lower - right\ corner, 
		x\  = \ 
            fraction\ of\ base\ where\ altitude\ intersects, 
		h\  = \ 
            height\ of\ triangle, \ 
		style\  = \ 
            options\ for\ Text
	*) 
	\ 
	{a = {0, 0}, b = {1, 0}, 
          x = 0.7, h = 0.6, 
	
          style = {FontSize -> 12, FontFamily -> "Arial", 
              FontColor -> RGBColor[0, 0, 1]}}, 
	
	 (*
		c\  = \ 
            upper\ vertex\ of\ triangle, 
		d\  = \ 
            lower\ end\ of\ altitude
	*) 
	
	d = x\ \((b - a)\); 
        c = d + {0, h}; 
	
        Show[{
			
			 (*\ 
              draw\ triangle\ *) \ \ 
						Graphics[
              Line[{a, b, c, a}]], 
			 (*\ 
              draw\ altitude\ *) 
						Graphics[{Dashing[{0.02, 
                    0.01}], Line[{d, c}]}], 
			
			 (*\ 
              label\ lengths\ and\ angles\ *) 
	\ \ \ Graphics[{
					Text["a", \(a + c\)\/2 + {\(-0.05\), 0}, 
                  TextStyle -> 
                    style], 
					Text["b", \(a + b\)\/2 + {0.0, \(-0.05\)}, TextStyle -> 
                    style], 
					Text["c", \(b + c\)\/2 + {0.05, 
                      0}, TextStyle -> 
                    style], 
					Text["h", \(d + c\)\/2 + {\(-0.05\), 0}, TextStyle -> style], 
					Text["α", 
                  b + {0.03, \(-0.03\)}, 
                  TextStyle -> style], 
					Text["β", 
                  c + {0.0, 0.03}, 
                  TextStyle -> style], 
					Text["γ", 
                  a + {\(-0.03\), \(-0.03\)}, 
                  TextStyle -> style]
				}]
	}, 
          PlotRange -> All, 
          AspectRatio -> Automatic]
	];\)\)
\(	\)

Example: quark model

The quark model suggests that protons (and other particles in the hadron family) contain three constituents which each carry intrinsic angular momentum, which is called spin and is displayed as an arrow.  In addition, quarks have two internal coordinates whimsically known as flavor and color.  Two flavors are needed for the proton, two u or up quarks and one d or down quark, and three primary colors must be combined to form a net colorless (white) object.  The module DrawQuark displays a single quark as a colored circle labeled by flavor superimposed upon a spin arrow.  The module DrawHadron places three quarks within a circular or elliptical outline.  Our purpose here is not to explain the physics of this model, but to demonstrate that some relatively sophisticated illustrations can be created fairly easily using graphics primitives.

This somewhat more complicated example employs the graphics primitives Circle and Arrow in addition to Text.  Note that Arrow is found within a package by the same name.  These modules are little too long to explain in much detail — please study them until their operation becomes apparent.

Needs["Graphics`Arrow`"]

Clear[DrawQuark, u, d];
DrawQuark[position_, flavor_, color_, spin_] := 
        Module[{a = {0, 0}, 
            labelStyle = 
              Sequence[FontSize -> 18, FontWeight -> "Bold", 
                FontSlant -> "Italic", 
                FontFamily -> "Times"]}, 
          Show[{Graphics[{Thickness[0.02], 
                  Arrow[position - {0.01, 0.02}, position + {0.01, 0.02}, 
                    HeadScaling -> Relative]}], 
              Graphics[{PointSize[1], 
                  RGBColor[(color /. List -> Sequence)], 
                  Point[position]}], 
              Graphics[Text[StyleForm[flavor, labelStyle], position]]}, 
            AspectRatio -> Automatic, 
            ImageSize -> 60]];

Clear[DrawHadron];
DrawHadron[name_, positions_, flavors_, colors_, spins_, 
          deformation_, opts___Rule] := 
        Module[{n, quarks = {}, radius = 0.5, arrowLength, begin, end, 
            labelStyle = 
              Sequence[FontSize -> 18, FontColor -> GrayLevel[0], 
                FontWeight -> "Bold", 
                FontSlant -> "Italic", 
                FontFamily -> "Times"]}, n = Length[positions]; 
          arrowLength = 0.75 radius; 
          Do[begin = 
              positions[[i]] - 
                0.5  arrowLength {Cos[
                      spins[[i]]], 
                    Sin[spins[[i]]]}; 
            end = positions[[i]] + 
                0.5  arrowLength {Cos[
                      spins[[i]]], 
                    Sin[spins[[i]]]}; 
            AppendTo[quarks, 
              Graphics[{Thickness[0.01], 
                  Arrow[begin, end, HeadScaling -> Relative], 
                  PointSize[0.175], 
                  RGBColor[
                    colors[[i]] /. 
                      List -> Sequence], 
                  Point[positions[[i]]], 
                  Text[StyleForm[
                      flavors[[i]], 
                      labelStyle], 
                    positions[[
                      i]]]}]], {i, 1, n}]; 
          Show[{Graphics[
                Circle[{0, 0}, {(1 + deformation) radius, radius}]], 
              quarks, Graphics[
                Text[StyleForm[name, labelStyle], {0, -1.2 radius}]]}, 
            opts, AspectRatio -> Automatic]];

The following statement creates a graphics array that compares quark models for the proton, neutron, and \(TraditionalForm\`\(Δ\^+\)\) particles.  Notice that the last is shown as an ellipse because it is believed to be slightly deformed (nonspherical).

\(\(DisplayTogetherArray[{
	
          DrawHadron[
            proton, {{0. , 0.2}, {\(-0.2\), \(-0.2\)}, {0.3, \(-0.1\)}}, {u, 
              u, d}, {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, {60\ Degree, 
              120\ Degree, \(-60\) Degree}, 0. ], 
		DrawHadron[
            neutron, {{0. , 0.2}, {\(-0.2\), \(-0.2\)}, {0.3, \(-0.1\)}}, {d, 
              d, u}, {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, {60\ Degree, 
              120\ Degree, \(-60\) Degree}, 
            0. ], 
		DrawHadron[\*""\!\(\(Δ\^+\)\)"", {{0. , 0.2}, {\(-0.2\), \(-0.2\)}, {0.3, \(-0.1\)}}, {u, u, 
              d}, {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, {60\ Degree, 
              120\ Degree, 60  Degree}, \(-0.1\)]}];\)\)

Of course, this figure could also be created, perhaps more easily, using an independent drawing program and then imported into a Mathematica notebook.

\(TraditionalForm\`\(f\&~\)\_n[x] = \ 
      4\/π\ \ \(∑\+\(k = 1\)\%n Sin[\((2  k - 1)\) x]\/\(2  k - 1\)\)\)

\(TraditionalForm\`f[n, d, λ, θ] = 
      Sin[n\ π\ \(d\/λ\) Sin[θ]]\^2\/Sin[π\ \(d\/λ\) Sin[θ]]\^2\)

I[θ]  =  
      (Subscript[I, 0]) (Subscript[f, n])[d, λ, θ] g[
          a, λ, θ]

\(TraditionalForm\`f\_n[d, λ, θ] = 
      Sin[n\ π\ \(d\/λ\) Sin[θ]]\^2\/Sin[π\ \(d\/λ\) Sin[θ]]\^2\)

\(TraditionalForm\`g[a, λ, θ] = 
      Sin[π\ \(a\/λ\) Sin[θ]]\^2\/\((π\ \(a\/λ\) Sin[θ])\)\^2\)

and here is an example of an envelope figure with logarithmic vertical scale.

\(TraditionalForm\`\(ψ\_\(n,ℓ,\ m\)\)(
        r, θ, ϕ) ∝ e\^\(\(-κ\)\ r\)\ \((κ\ r)\)\^ℓ\ \(\(L\_\(n - ℓ - 
                1\)\%\(2\ ℓ + 1\)\)(
          2\ κ\ r)\)\ \(\(Y\_ℓ\%m\)(θ, ϕ)\)\)