Mathematica: labeling points on graph

Doing the same thing, efficiently

Mathematica does not provide a way to "post-process" a graph -- to add points and text manually after the graph exists. Instead, you must generate the components of the graph, including additional points and text, and display them all together, i.e.,
  1. make the line graph of the function (using Plot)
  2. graph individual points (using ListPlot)
  3. make text labels for the necessary points (using Text)
  4. combine 1, 2, and 3 into a single graph

Here is the downloadable sample Mathematica notebook from which the following is taken.


Plotting a function, and plotting individual points, is easy in Mathematica. Labelling points on the graph with text is harder, because of issues like choice of font/size and text placement. Labelling points with formatted mathematical expressions, and placing the label nicely, involves asthetics that are hard to program. You are the judge of whether it is worth the trouble, but it does get easier with experience.

The following function   f(x)   will be used to illustrate all these things:

	f[x_] := (x+2)(x-1)(x-3)
	basicplot = lot[ f[x] , {x,-8,8} ];

	Solve[ f[x] == 6 ]


1. Step by step

return to top

1.1 Quick illustration

Notice that the graph above has been named "basicplot". Giving names to graphs makes it easy to combine them later using Show. Here is the definition of a blue dot at point [Graphics:pp_gr_5.gif] plus a label, superimposed on the basic plot:

[Graphics:pp_gr_6.gif]

[Graphics:pp_gr_7.gif]

[Graphics:pp_gr_8.gif]

return to top

1.2 Finding and plotting the "interesting points"

A nice graph should be clipped so that it shows the "interesting points" without a lot of extra empty space around the edges. So the first order of business is to find the interesting points; the zeroes, minima, maxima, and points of inflection:

[Graphics:pp_gr_9.gif]
[Graphics:pp_gr_10.gif]
[Graphics:pp_gr_11.gif]
[Graphics:pp_gr_12.gif]

Put these x values together into a single list, and calculate their corresponding y values.

[Graphics:pp_gr_13.gif]
[Graphics:pp_gr_14.gif]
[Graphics:pp_gr_15.gif]
[Graphics:pp_gr_16.gif]

A "good" graph of f(x) will include all these points, plus just a bit extra space on all four edges, say, 15% of the size of the exact box containing only those points. So we can use the extreme values of x and y to define a good range for plotting the function, like this:

[Graphics:pp_gr_17.gif]
[Graphics:pp_gr_18.gif]
[Graphics:pp_gr_19.gif]

Call the plot of f(x) "graph1", and the plot of the points "graph2" (we use the PlotStyle option to make big blue dots!), then combine them to make "graph3":

[Graphics:pp_gr_20.gif]

[Graphics:pp_gr_21.gif]

[Graphics:pp_gr_22.gif]

[Graphics:pp_gr_23.gif]

return to top

1.3 Adding Labels to the graph

The combined graph above should be good enough, but if you really want to paste text labels onto the graph, it is certainly possible. Use Graphics[Text[...]] to create graphics items which can be combined with graph1 and graph2. You can always resize the plot using your mouse; do so before you try to fine-tune the offset for the labels!

[Graphics:pp_gr_24.gif]
[Graphics:pp_gr_25.gif]

[Graphics:pp_gr_26.gif]

...And you can do the same thing for each point. Doing one or two labels this way is OK, but you might want to automate the process a bit if you intend to label lots of points.

return to top


2. Doing the same thing, but more efficiently

This section is only of interest if you want to learn better ways to do this sort of thing in the future. The real power of Mathematica becomes apparent when you define your own functions to do complicated stuff, and when you learn to use powerful commands like Map. The function "Map" helps to automate work by applying a function to every item in a list. So if we can define a function which creates a text label for a given pair of x-y coordinates, Map can be used to create text labels for all of the interesting points at once.   View the online documentation for Map (and function definitions) or read about them as part of the ``Basics'' web pages.

return to top

2.1 Define the function ipoint

The first function finds the "interesting points" of a given function; let's call it "ipoints". (This uses the function Solve, which works great for polynomials, but not for other functions, so for nonpolynomial functions you would have to work harder; perhaps use FindRoot and FindMinimum, For polynomials of degree 5 or above, use NSolve.) Some roots may be complex, so function "realnumber" will be used to weed out complex (ungraphable!) x values:

[Graphics:pp_gr_27.gif]

Let's see if it works with our sample function:

[Graphics:pp_gr_28.gif]
[Graphics:pp_gr_29.gif]

Cool! Use these values to calculate the corresponding y values:

[Graphics:pp_gr_30.gif]
[Graphics:pp_gr_31.gif]
[Graphics:pp_gr_32.gif]
return to top

2.2 Define the function nicerange

The next function, "nicerange", will be defined for graphing purposes, to find the range which includes all the given values plus p% extra on each end:

[Graphics:pp_gr_33.gif]

Here's what the function yields for the x values, with 15% padding on both ends:

[Graphics:pp_gr_34.gif]
[Graphics:pp_gr_35.gif]

This will be used with the PlotRange option in the plotting commands.

return to top

2.3 Define the function xylabel

This function will create an (x,y) coordinate label -- a graphics object -- given the value {x,y} and also an offset pair used by Text: "Text[expr, coords, offset] specifies an offset for the block of text relative to the coordinates given". Font size 9 seems to work well:

[Graphics:pp_gr_36.gif]
[Graphics:pp_gr_37.gif]
return to top

2.4 Making the complete graph, using our functions

1. In order to suppress the display of intermediate plots, use the option "DisplayFunction->Identity. Then, when all the parts (plot, points, labels) are to be assembled with Show, use the option DisplayFunction->$DisplayFunction".

2. The offset values for the labels are the one part that will still be adjusted by eye. This could be automated, but the function would be even more mysterious than those defined so far...

3. Let's define an entirely new polynomial function g(x) to ensure that we don't reuse any earlier graphics.

[Graphics:pp_gr_38.gif]
return to top

2.5 -- First try

[Graphics:pp_gr_39.gif]
[Graphics:pp_gr_40.gif]
[Graphics:pp_gr_41.gif]

[Graphics:pp_gr_42.gif]

return to top

2.6 -- Refinement

It looks like more room is needed on the sides and top and bottom of the graph . The first attempt used 11% but let's increase that to 20%:

[Graphics:pp_gr_43.gif]

Next, the labels need to be offset better than this; they collide with the axes and with each other Try:

[Graphics:pp_gr_44.gif]

Now make the graphs again. Throw in another big label:

[Graphics:pp_gr_45.gif]

[Graphics:pp_gr_46.gif]