\makeatletter \def\MP{MetaPost} \def\foreign{\em} \def\eg{{\foreign e.g.~}\ignorespaces} % e.g. \DeclareRobustCommand\META{\textlogo{META}} \newsavebox{\boxdef} \newenvironment{BDef}{\begin{lrbox}{\boxdef}\def\arraystretch{1.0}% \begin{tabular}{@{}l@{}l@{}l@{}}}% {\end{tabular}\end{lrbox}% \BCmd\fbox{\usebox\boxdef}\endBCmd} % i hate this whole coding section! \newenvironment{BCmd}{\@beginparpenalty-\@lowpenalty\fboxsep=3pt\flushleft} {\@endparpenalty\@M\@topsepadd 10pt\relax \endflushleft} \makeatother \def\Mpack#1{\texorpdfstring{\textsf{#1}}{#1}} \let\Lpack\textsf \let\Mmpack\textsf \let\Mcmd\texttt \let\mMcmd\texttt \let\Author\relax \def\Program#1{\textsf{#1}} \let\mMPcmd\texttt \let\MPcmd\texttt \def\PreambleCommands{input graph} \title{A tutorial on using \MP's \Mpack{graph} package} \author[Sebastian Rahtz]{Sebastian Rahtz\\7 Stratfield Road\\Oxford OX2 7BG\\UK\\\texttt{s.rahtz@elsevier.co.uk}} \begin{Article} \section{Introduction} \MP{} is a sibling program to \MF, which replaces the bitmap output of the latter with PostScript and is designed more as a general-purpose drawing language than a font creation package. Although it has been around for five years or so (it has been Don Knuth's tool of choice for drawing for some time), it has only recently started becoming generally available for most users. With the release of Web2c version 7.0, \MP{} is integrated into the standard Unix and Windows 32 \TeX{} distribution, and it is also part of the CMacTeX and OzTeX packages for the Macintosh. Although many people find general-purpose drawing languages quite forbidding and counter-intuitive, creating nice graphs from simple data files is a common task, and the purpose of this short tutorial\footnote{This material is taken from chapter 3 of \emph{The \LaTeX{} Graphics Companion}, by Michel Goossens, Sebastian Rahtz and Frank Mittelbach, published by Addison-Wesley in March 1997. Reprinted by permission of Addison-Wesley.} about \MP{} is to describe its graphing support. The high-level library of \MP{} macros to draw graphs was written by \MP's author, John Hobby, to provide a sophisticated interface comparable to \Program{grap} (see Bentleyand Kernighan, 1984). It is hoped that by giving examples of its use, more people can be encouraged to try it and (who knows?) start to explore more of \MP{} for other sorts of drawing. \MP{} is well documented in Hobby (1992), and the graph package is described in Hobby (1993); both these documents normally form part of a \MP{} distribution. \section{Getting started} To start, a quick recipe for writing a \MP{} input file. Unlike \TeX, there are no backslashes or curly braces, and commands normally end with semicolons; at the start of your file, you need to load the \texttt{graph} package with an \texttt{input} command, and the file is completed with \texttt{end;}. In between you can have one or more drawings inside \texttt{beginfig}\ldots \texttt{endfig;}, where \texttt{beginfig} has a parameter (in round brackets) of a number which will be the suffix of the output PostScript file. A graph comes inside \texttt{draw begingraph} \ldots \texttt{endgraph;}, where \texttt{begingraph} has a parameter of two dimensions which set the width and height of the graph. \MP{} takes care of scaling all the drawing to fit in this area. Thus a complete \MP{} file might look like this: \begin{sverbatim} input graph beginfig(1) draw begingraph(2.5in,1.75in); gdraw "yearm.dat"; endgraph; endfig; end; \end{sverbatim} If we save this as \texttt{test.mp}, and run it with the command \texttt{mpost test.mp}, the output (under Unix) looks something like this: \begin{fverbatim} darkstart:~/# mpost test.mp This is MetaPost, Version 0.632 (Web2c 7.0) (test.mp (/cdrom/share/texmf/metapost/base/graph.mp (/cdrom/share/texmf/metapost/base/marith.mp (/cdrom/share/texmf/metapost/base/string.mp)) (/cdrom/share/texmf/metapost/base/format.mp (/cdrom/share/texmf/metapost/base/string.mp) (/root/tds/metapost/latexpp/texnum.mp))) [1] ) 1 output file written: test.1 Transcript written on test.log. \end{fverbatim} Labels or captions in a \MP{} drawing are often passed to \TeX{} to process behind the scenes, as we shall see presently, and the result is a PostScript file we can include in our \TeX{} in the ordinary way. It is assumed that the reader can find out how to do this. Rather than showing the trivial result of that test, let us consider a slightly more sophisticated real graph (using data from the Protestant Cemetery, Rome---see Rahtz (1988)) which looks like this (henceforth we only show the \MP{} code between \texttt{begingraph} and \texttt{endgraph}): \begin{MPExample*}{} draw begingraph(2.5in,1.75in); gdraw "yearm.dat" dashed evenly; gdraw "yearw.dat"; glabel.lft (btex (solid) Women etex, 1960,30); glabel.lft (btex (dashed) Men etex ,1870,30); glabel.bot (btex Number of burials per year ($n \approx 4300$) etex,OUT); endgraph; \end{MPExample*} This shows some of the main features of the \Mpack{graph} package for plotting data from external data files and labeling. The command \texttt{gdraw} (which can be used several times in succession) is followed by a file name; it reads data values (two per line, giving an $x$ and $y$ coordinate) from that file, and plots the resulting line. The effect can be varied with various modifiers --- here we used \texttt{dashed evenly}. The command \texttt{glabel}, to place some captioning text, has a prefix (separated by .) which indicates where on the graph it is to go (\texttt{lft} = `left', \texttt{bot} = `bottom' etc). It is followed by an expression inside round brackets of text, an $x$ coordinate, and a $y$ coordinate. The special coordinate pair of \texttt{OUT} means it will be placed neatly outside the graph area. You can supply literal text in quotes, or have it processed by \TeX{} by bracketing it with \texttt{btex} \ldots \texttt{etex} (no quotes around the text in this case). The \texttt{graph} package can take care of: \begin{itemize} \item automatic scaling of data; \item automatic generation and labeling of tick marks or grid lines; \item multiple coordinate systems in the same picture; \item linear and logarithmic scales; \item plotting with arbitrary symbols; \item handling multiple columns in the same data file, with user-specified procedures. \end{itemize} \section{Variations in basic graphing} If \Mcmd{gdraw} is followed by a \mMcmd{plot} command, a symbol can be drawn at each coordinate instead of a continuous line; the symbols is technically a \MP{} ``picture'', i.e. in practice some text which can be typeset by \TeX, as the following variation shows:% \begin{MPExample*}{} draw begingraph(2.5in,1.75in); gdraw "yearm.dat" plot btex $\bullet$ etex; gdraw "yearw.dat" plot btex $\circ$ etex; glabel.bot (btex Burials etex,OUT); glabel.lft (btex Number etex rotated 90,OUT); endgraph; \end{MPExample*} For this graph we also rotated the label for the $y$ axis by 90\textdegree{} using a modifier to \texttt{btex} \ldots \texttt{etex}. \subsubsection{Frames, ticks, grids and scales} By default, graphs have a frame on all sides, no grid, and tick marks on the bottom and left. The frame can be altered with the \mMcmd{frame} command, which has a set of optional suffixes. Grid lines and ticks are controlled with \Mcmd{autogrid}: \begin{BDef} \mMcmd{autogrid}(\emph{$x$ specification},\emph{$y$ specification}) \end{BDef} \noindent The specifications can have the values \mMcmd{grid}, \mMcmd{itick} or \mMcmd{otick}, which produce grid lines, inner ticks, or outer ticks; they can be suffixed with \texttt{.top} or \texttt{.bot} for the $x$ axis and \texttt{.lft} and \texttt{.rt} for the $y$ axis, as the following example shows: \begin{MPExample*}{} draw begingraph(2.5in,1.75in); gfill "yearw.dat" withcolor red; autogrid(grid.bot,itick.rt) withcolor .5white; frame.llft; endgraph; \end{MPExample*} To override \Mpack{graph}'s choice of where to put tick marks and how to write labels, you can add explicit ticks with \mMcmd{itick} or \mMcmd{otick} and grid lines with \mMcmd{grid}. These have the same suffixes as \Mcmd{autogrid} and are followed by a \MP{} picture variable containing a label or a \Mcmd{format} command, and a coordinate. \Mcmd{format} is used to control how numbers are printed: \begin{BDef} \mMcmd{format}(\emph{specification},\emph{number}) \end{BDef} \noindent The \emph{specification} consists of an optional initial string, a percent sign, an optional number indicating precision (default 3), a conversion letter (\texttt{e}, \texttt{f} or \texttt{g}) and an optional final string. The conversion letter determines whether or not scientific notation is used; \texttt{\%g} will use decimal format for most numbers. How the scientific notation used by \Mcmd{format} is typeset depends on a \MP{} macro called \Mcmd{init\_numbers} (see manual); since this uses the \MPcmd{btex}\ldots\MPcmd{etex} system, you may need to look at it carefully if you are concerned about precisely which fonts are used. The next graph shows both types of explicit labeling; we have to remember to turn off the normal marks at the end!% \begin{MPExample*}{} draw begingraph(2.5in,1.75in); gfill "yearw.dat" withcolor red; for y=10,20,30: itick.lft(format("%g",y),y); endfor otick.top("19th century",1850); otick.top("20th century",1950); frame.llft; autogrid(,); endgraph; \end{MPExample*} The labeling can also be changed by \Mcmd{setcoords} \begin{BDef} \mMcmd{setcoords}(\emph{$x$ style},\emph{$y$ style}) \end{BDef} The parameters for $x$ and $y$ can be set to \texttt{log}, \texttt{-log}, \texttt{linear}, or \texttt{-linear}. While the program's scaling of data to fit the graph usually gives the right results, it can be overridden with \Mcmd{setrange}: \begin{BDef} \mMcmd{setrange}(\emph{min},\emph{max}) \end{BDef} You need to supply the minimum and maximum coordinates. The special constant \mMcmd{origin} is a useful shorthand for (0,0). To leave any value to be figured out by \MP, specify \mMcmd{whatever}. If you specify no range at all, \MP{} works it out from the data values and adds a small border. \subsubsection{Reading data files} Although the \Mcmd{gdraw} and \Mcmd{gfill} commands often suffice, we can get more control over the data read from a file by using \Mcmd{gdata}: \begin{BDef} \mMcmd{gdata}(\emph{filename}, \emph{variable}, \emph{commands}) \end{BDef} The \emph{commands} are executed for every line of data in \emph{filename}, with the values for each column available as, \eg $c1$, $c2$ \ldots $c\mbox{n}$ for the variable name $c$. \emph{filename} is a \META{} string, so simple names should be enclosed in quotes (file names can also be computed from \META{} variables.) Using some more data from the Protestant Cemetery in which each line consists of a person's age at death, we can show the distribution of mortality by age by accumulating data in an array and using that to create a path:% \begin{MPExample*}{} draw begingraph(2.5in,1.5in); numeric p[]; path r; for j := 0 upto 100: p[j]:=0; endfor gdata ("ages.dat",y, age:=(scantokens y1); p[age]:=p[age] + 1;); r:=(0,0) for j := 1 upto 100: --(j,p[j]) endfor; gdraw r; frame.llft; endgraph; \end{MPExample*} The only complications are the need to initialize the array and the conversion of the string representation read from the data file into a numeric value with \mMPcmd{scantokens}. When \mMcmd{gdata} reads data files, it stops when it reaches a blank line or end of file; if you start \Mcmd{gdata} again with the same file name, it carries on reading another set of data. This allows you to put all your data sets in one file, but use it with care. One problem is that data files remain open if there is a blank line at the end, since \MP{} thinks some more data might follow; if you have many small data files, this situation can cause a \MP{} error---check the end of your files. This display in the example above is not very readable; it might be better to accumulate data per decade of death from the file. As this gets a little more complicated, we abstract the job into a \MP{} macro called by the \Mcmd{gdata} command: \begin{MPExample*}{} draw begingraph(2.5in,1.75in); setrange(origin,(100,100)); numeric p[]; path r; for j := 0 step 10 until 100: p[j]:=0; endfor def check(expr age) = if age < 100: xage:=round(age/10) * 10; p[xage]:=p[xage] + 1; fi enddef; gdata ("ages.dat",y, check((scantokens y1));); r:=(0,0) for j := 0 step 10 until 100: --(j,p[j]) endfor --(100,0); gfill r -- cycle withcolor blue; frame.llft; endgraph; \end{MPExample*} It is often useful to accumulate points on a path for each line read from the data file; the macro \mMcmd{augment} is provided for this. Given a suffix of a variable name of type ``path'' and a parameter of a coordinate, \Mcmd{augment} creates the path if it does not exist or adds the point to an existing path. We use this to show the gravestone data again, this time processed to provide separate figures of deaths per decade for women (column 2) and men (column~3): \begin{verbatim} 1800 3 6 1810 9 15 1820 26 64 1830 31 88 ... \end{verbatim} For each decade, we keep track of the last point reached and augment separate paths for male and female; these are then shaded in different colors to show how the male and female patterns vary over time. We need to know the last decade in order to establish a sensible corner for the filled shape. The female pattern appears as a dotted line on top of the male shading. \begin{MPExample*}{} path m,w,last; draw begingraph(3in,2in); setrange((1800,0),(whatever,whatever)); gdata ("decade.dat",y, last:=((scantokens y1),0); augment.w(y1,y2); augment.m(y1,y3);); gfill (1800,0)--w--last--cycle withcolor red; gfill (1800,0)--m--last--cycle withcolor green; pickup pencircle scaled 3pt; gdraw w dashed withdots; pickup pencircle scaled .75pt; glabel.bot (btex Number of burials per decade ($n \approx 4300$) etex,OUT); endgraph rotated 90; \end{MPExample*} The example demonstrates that the graph macros return a \META{} picture that can then be transformed (in this case rotated). \subsubsection{Different graph types} With a little effort, \Mpack{graph} can draw bar charts; to demonstrate this, we copy a chart from Goossens et~al.\ (1994), p.~287, that was made with the \LaTeX{} \Lpack{bar} package. Our technique is to make a single path out of all the bars and fill the result at the end:% \begin{MPExample*}{} path s; numeric x,y; draw begingraph(2.5in,1.75in); gdata ("students.dat",c, x:=(scantokens c1) * 12; y:=(scantokens c2); augment.s((x-5,0)-- (x-5,y)-- (x+5,y)-- (x+5,0)); if y < 0: glabel.top(c2,(x,0)); fi if y > 0: glabel.bot(c2,(x,0)); fi ); gfill s--cycle withcolor .5white; frame.llft; endgraph; \end{MPExample*} \noindent We explicitly work out the corners of each bar and allow for their width by multiplying the $x$ values by 12; the bars themselves span 5 units on either side of the data point, so there is a gap of 2 units between each one. A similar technique is used in the next chart which shows the number of pages in chapters of \emph{The \LaTeX{} Graphics Companion}; this time we draw each bar separately, so that they can be shaded according to the values. The work is delegated to a macro, which also prints a rotated label for each bar. Because explicit $x$ labels are supplied, labeling of the $x$ axis is suppressed. \begin{MPExample*}{} path m; numeric n,width; width:=20; defaultscale:=0.6; n:=0; def bar(expr name,value) = gfill(n,0)--(n,value)-- (n+width,value)--(n+width,0)--cycle withcolor (value/100,value/100,value/100); picture p; p = name infont defaultfont scaled defaultscale rotated 90; glabel.rt (image(unfill bbox p; draw p),(n,10)); n:=n+width; enddef; draw begingraph(2.5in,1.75in); setrange((0,0),(11*width,100)); autogrid(,otick.lft); gdata("chap.dat",c,bar(c1,(scantokens c2));); endgraph; \end{MPExample*} The string value read from the first data column is put into a \MP{} picture variable by using the low-level command \mMPcmd{infont}. This lets us use \MPcmd{bbox} technique to give the extent of the text, which is made white with \MPcmd{unfill}. \mMPcmd{image} is a useful macro that yields the picture resulting from a sequence of drawing commands; we use that as a label. The data for this graph starts as follows: \begin{verbatim} graphics 28 stdgraph 26 xypic 28 mf 26 ... \end{verbatim} We can also present our earlier ``decade'' data as a dual bar chart, with male and female figures side by side. To do this we maintain two separate paths, fill one and leave the other as an outline: \begin{MPExample*}{} path m[],w[]; def wcheck(expr decade,value) = augment.w1(decade,0); augment.w1(decade,value); augment.w1(decade+5,value); augment.w1(decade+5,0); enddef; def mcheck(expr decade,value) = augment.m1(decade+5,0); augment.m1(decade+5,value); augment.m1(decade+10,value); augment.m1(decade+10,0); enddef; draw begingraph(3.75in,2in); gdata ("decade.dat",y, wcheck((scantokens y1),(scantokens y2)); mcheck((scantokens y1),(scantokens y3));); gfill m1--cycle; gdraw w1; glabel.bot (btex Number of burials per decade ($n \approx 4300$) etex,OUT); frame.llft; endgraph rotated 90; \end{MPExample*} With care, we can even draw pie charts using similar ideas. The following example \label{mppie} reads data about gravestones in the Protestant Cemetery in the following form: \begin{verbatim} Romanian 1 0.02796420582 Czech 2 0.05592841163 ..... Italian 391 10.93400447 German 508 14.20581655 unknown 599 16.75055928 English 1462 40.8836689 \end{verbatim} \noindent Here the second column is the number of gravestones per nationality and, to make the code less complicated, the third column is the percentage of the total. For each pie wedge, we use the \mMPcmd{buildcycle} macro to find the smallest enclosed shape from the union of a whole circle and two lines extending from the center at the starting and closing angle of the segment. The fill color of the wedge is derived from the percentage. \begin{MPExample*}{} numeric r,last; path c,w; r:=5; c:=fullcircle scaled 2r; last:=0.0; def wedge (expr lang,value,perc) = numeric current,n,half,xoff,yoff; picture p; n:=perc*3.6; current:=last+n; half:=last+(n/2); w:=buildcycle((0,0)--(2r,0) rotated last, c, (2r,0)--(0,0) rotated current); gfill w withcolor (0.8-(perc/100),0.8-(perc/100),0.8-(perc/100)); gdraw w; if perc > 5: p = lang infont defaultfont scaled defaultscale; glabel(image(unfill bbox p; draw p), 3/4r*dir(half)); fi; last:=current; enddef; draw begingraph(3in,3in); defaultscale:=0.7; gdata ("langs.dat",c, wedge(c1, (scantokens c2), (scantokens c3));); autogrid(,); frame withcolor white; endgraph; \end{MPExample*} The placement of the labels in the pie bears a little examination; they are placed in the center of each wedge, three quarters of way along the radius. Another type of graph has a linear $x$ scale and uses the $y$ axis simply to compare sets of data. The following graph uses our cemetery data to show the first and last occurrences of each type of gravestone. The code is straightforward except that we draw the lines with a different sized pen (with square ends) and revert to a thin line to draw the scale and frame (only on the bottom, since the $y$ axis is not linear). \begin{MPExample*}{} draw begingraph(2.5in,2.5in); n:=10; defaultscale:=0.7; pickup pensquare scaled 3pt; setrange((1700,0),(whatever,whatever)); gdata("stones.dat", s, gdraw ((scantokens s2),n)-- ((scantokens s3),n); glabel.lft(s1,(scantokens s2)-3,n); n:=n+16;); pickup pensquare scaled .5pt; frame.bot; autogrid(otick.bot,); endgraph; \end{MPExample*} The data, ranked in order of first occurence, starts like this: \begin{verbatim} Chest 1738 1966 Head 1765 1986 Column 1766 1960 Plaque-on-base 1775 1986 Pedestal 1786 1967 Plaque-in-ground 1794 1985 \end{verbatim} Our last example is more unusual. We want to plot data from a survey grid and shade each grid square according to its data value; in the data file the first two columns are the coordinates of the lower left corner of the grid square, the third column is the absolute data value, and the fourth column is a percentage version: \begin{verbatim} 2 1 102 85 2 2 10 98 2 3 110 84 2 4 112 83 2 5 114 83 ... \end{verbatim} The text is printed in white or black depending on the percentage. \begin{MPExample*}{} def sq(expr x,y,num,perc) = gfill(x,y)--(x+10,y)-- (x+10,y+10)--(x,y+10)--cycle withcolor (perc/100,perc/100,perc/100); glabel(num,(x+5,y+5)) if perc < 50: withcolor white fi; enddef; defaultscale:=0.7; draw begingraph(70mm,80mm); setrange((20,10),(110,110)); autogrid(,); gdata ("pot.dat",c, sq((scantokens c1)*10, (scantokens c2)*10, c3, (scantokens c4));); endgraph; \end{MPExample*} \begin{thebibliography}{99} \bibitem{Bentley/Kernighan:1984} Bentley, J. and Kernighan, B. 1984. \newblock \emph{{GRAP} --- a language for typesetting graphs}. \newblock Computing Science Technical Report 114, AT\&T Bell Laboratories, Murray Hill, NJ. \bibitem{Companion} Goossens, M., Mittelbach, F. and Samarin, A. 1994. \newblock \emph{The {\LaTeX} companion}. \newblock Reading, MA: Ad{\-d}i{\-s}on-Wes{\-l}ey. \bibitem{Hobby:MP} Hobby, J.~D. 1992. \newblock \emph{A user's manual for MetaPost}. \newblock Computing Science Technical Report 162, AT\&T Bell Laboratories. \bibitem{Hobby:MPG} Hobby, J.~D. 1993. \newblock \emph{Drawing graphs with MetaPost}. \newblock Computing Science Technical Report 164, AT\&T Bell Laboratories. \bibitem{Rahtz:1988} Rahtz, S. 1987. \newblock The Protestant Cemetery, Rome: a study undertaken under the auspices of the Unione Internazionale degli Istituti di Archeologia, Storia e Storia dell'Arte in Roma. \newblock \emph{Opuscula Romana}, \textbf{16}, 149--167. \end{thebibliography} \end{Article}