Metapost
From Liki
Metapost is an extremely powerful and versatile picture drawing language based on the Metafont language used in TeX. Lets face it - graphics in TeX is tough. The picture environment is quite limited, and even xypic is no picnic to use. If you require only rudimentary graphics, then xfig should suffice, which has the advantage of having a graphical front end, but Metapost allows you to do near anything.
If you don't know any Metapost yet, consider learning Asymptote, which pitches itself as Metapost's successor.
Contents |
[edit] Basic Structure
The basic structure of a metapost file, usually ended with a .mp extension is
beginfig(1); graphic commands... endfig; beginfig(2); more graphic commands... endfig; end;
where you can have any number of figures in one metapost file. Each command line must end with a semicolon like in C. Once your file is complete you run
mpost file.mp
which will create file.1, file.2,... one for each beginfig in the metapost, and file.log, which is useful for debugging when your metapost doesn't process correctly. The files file.1, etc... are eps files and are ready to be viewed with ggv or included in your latex document. Comments may be added by beginning a line with a %.
Note that emacs knows that .mp extension belong to metapost, so if you save your files with that extension you will get syntax highlighting.
[edit] Drawing
The arena for metapost drawing is a 2-D grid (but don't be dismayed, 3-D graphic can be made as well). Drawing things is as simple as connecting the dots between points on the grid. For example
% draw a square draw (0,0) -- (10,0) -- (10,10) -- (0,10) -- (0,0); % draw a point draw (5,5) scaled 5;
draws a square with big dot in the center. Then (--) makes a straight line between the points. The size of the grid defaults to 'Postscript points' (pp) which are 1/72 of an inch (this is slightly different than a printer's point (pt) which is 1/72.27 of an inch!). Anyway, different units can be used, such as in, cm, and mm. It's cumbersome to write cm, say, all the time. We will see ways around this later. The default size of a drawn point is also 1pp, so the 'scale 5' makes it 5 times bigger (and more visible).
You can connect your dots with .. instead of -- to get rounded edges (cubic Bezier). You can also use --- and ... which mean, respectively "smooth connection between straight line and rest of curve" and "inflection-free path between points if possible". It's probably easier to judge their meanings by trying them out.
[edit] Variables
Variables is what makes metapost so wonderful. You can use variables for anything from points to whole figures! Variable assignments are made with the := operator, unless you are defined pairs (points), in which case you use the = operator. variables need declarations, except for numeric ones since that is the default type. For exmaple
picture p; %declaration that p is picture variable u:=1cm; % define units (numeric variable) pair P[]; p0=(0,0); p1=(10,0)*u; p2:=(10,10)*u; p3:=(0,10)*u; % make points (pair variable) draw p0--p1--p2--p3--cycle; % draw square p := currentpicture; % turn what we have so far into a variable draw p rotated -30; % produce an exact copy rotated by 30 degrees cw
creates two squares - the second a perfect rotated copy of the first. Here we defined a variable which defined a fundamental unit of length (u:=1cm) to make defining points easier. We need only change u to change the scale for all the points.
We can also define macros like
def drawsquare(expr s) = draw unitsquare scaled s; enddef; vardef square(expr s) = s*s; enddef;
where vardef is used if the macro returns a value (like a function). The (expr a,b,c,...) specifies input parameters when the macro is called.
[edit] Labels and TeX
Yup, you can even embed TeX inside your pictures for labels and the like. Try doing that in xfig! First lets start with a plain label
label.pos("label text",<coordinates>)
where <coordinates> can be just a point like (0,0) or the midpoint of a line 1/2[A,B], where A and B are two points, or some other expression. 'pos' is a relative position indicator for the label which can be top, bot, lft, rt, or on the corners: ulf, urt, llf, lrt. We can add TeX to a label by putting TeX commands between the commands btex and etex:
label.bot(btex $ TeX commands $ etex,(0,0));
Note that this will only work for TeX commands, not LaTeX specific ones like \frac! If you need to use LaTeX commands you need to put the following at the top of the .mp file
verbatimtex
%&latex
\documentclass{article}
\begin{document}
etex
Note that the '%&latex' line is not a comment, though it starts with % - it is a command to use LaTeX, and that no \end{document} is necessary. Furthermore, the TeX will be typset in text style by default, so you'll need to add a \displaystyle inside the $'s so that your \frac's aren't squashed.
Note furthermore that if your metapost contains TeX then a standard postscript viewer will not be able to read it. This is no real limitation since you'll probably want these in a TeX document anyway. To view them, you'll have to wrap it in a TeX documents and view the DVI output, or convert that to ps (or you can use the script linked at the bottom of the page). Another option is to add the line 'prologues := 1' at the beginning of the mpost file, which will try to substitue postscript fonts for the TeX. This can be good for previewing, but the results are never satisfying.
Finally there is the dotlabel command, which works exactly as label, except it places a dot at the indicated point.
[edit] Transformations
We caught a glimpse into transformation in the last secting using rotations. We can specify a general affine transformation in the plane by a matrix T which has structure (the upper 2x2 part consists of linear transformations of the plane fixing the origin, and the right hand column vector is a displacement of the origin)
and each component can be specified by 'xxpart T = 1; ypart T = -3' and so on. An oftentimes more convenient way to specify a transformation is by describing the image under T of 3 points in the plane. For example, to specify the reflection about the line that passes through the points (1,0) and (0,1) we would have
transform T; %declaration (1,0) transformed T = (1,0); (0,1) transformed T = (0,1); (0,0) transformed T = (1,1);
although, such a reflection can also be specified by typing reflectedabout(p,q), where p and q are two points on the line.
[edit] Loops
Loops, variables, and transformation can make construcing complicated figures quite easy when you think of their construction in the right way. As an example
pair A,B,C; u:=3cm; A=dir(-30)*u; B=dir(90)*u; C=dir(210)*u; transform T; A transformed T = 1/6[A,B]; B transformed T = 1/6[B,C]; C transformed T = 1/6[C,A]; path p; p=A--B--C--cycle; for i=0 upto 60: draw p; p:=p transformed T; endfor;
creates a nesting of triangles that spiral towards the center with minimum effort! Here we have introduced the dir command which specifies a point on the unit circle with argument in degrees. The transformation defined moves each corner of the triangle 1/6 of the way to the the next corner and then the triangle is redrawn.
If you are using a loop to draw labels like $x_i$ for several i, take a look at TEX.mp (see page 4 of the spring 2005 MetaPost notes for a usage example). TEX.mp should be part of any post-2005 metapost distribution. Try `locate TEX.mp` to see if it's installed on your system, or look in metapost-1.002/texmf/metapost/base/ in the current MetaPost source.
[edit] Graphing Functions
Sometimes you just need plotted output from gnuplot or Maple, but they can be difficult to incorporate in a TeX document (especially Maple), and it's difficult to get nice (font matched) labels on those figures (again, especially in Maple). So, it would be nice to graph functions in Metapost - and indeed we can. Here is an example of a graph for a charging capacitor. It also makes axes, tick marks, appropriate labels, and even a dotted asymptote.
vardef exp(expr x) = (mexp(256)**x) enddef;
vardef f(expr x) = (1-exp(-x)) enddef;
u := 1cm;
numeric xmin,xmax,ymin,ymax;
xmin:=0; xmax:=4;
ymin:=0; ymax:=1.2;
% draw axis
draw (xmin,0)*u -- (xmax,0)*u;
draw (0,ymin)*u -- (0,ymax)*u;
% tickmarks
for i=0 upto xmax:
draw (i,-0.05)*u -- (i,0.05)*u;
label.bot(decimal(i),(i,0)*u);
endfor;
draw (-0.05,1)*u -- (0.05,1)*u;
label.lft(btex 1 etex,(0,1)*u);
% label axes
label.bot(btex $t/\tau$ etex,(xmax/2,-.25)*u);
label.lft(btex $\displaystyle \frac{Q}{Q_{max}}$ etex,(-.25,ymax/2)*u);
% graph label
label.top(btex Charging etex,(xmax/2,ymax)*u);
% graph the function pointwise
xinc := .1;
path pts_f;
pts_f := (xmin,f(xmin))*u
for x = xmin + xinc step xinc until xmax:
.. (x,f(x))*u
endfor;
draw pts_f withpen pencircle scaled 1;
% draw dotted line for full charge
draw (0,1)*u -- (xmax,1)*u dashed withdots;
This example puts together most of whats on this page. Note that metapost does not know the exponential function, but it does know how to raise powers (**) and it knows the value of e via mexp(x) = exp(x/256). It knows internally sind and cosd, which expect the argument in degress, not radians.
[edit] Hatching
For those of us with black and white printers, there's a hatching macro package. Run
$ locate hatching.mp
to see if you already have it installed.
Usage is somewhat nonintuitive, but it is explained in the readme and examples distributed with the package. Basic usage is like `fill', for example:
input hatching; beginfig(0); path P; P := fullcircle scaled 2cm; hatchoptions(withcolor blue); hatchfill P withcolor (45,2mm,-1pt) withcolor (-10,4mm,-2pt); hatchoptions(withcolor red dashed evenly); hatchfill P withcolor (-30,5mm,-1pt); endfig; end;
The `hatchoptions()' commands pick the type of line used to draw the hatch. The first hatchfill draws hatching at 45dg with a spacing of 2mm between the lines and a line thickness of 1pt. The thickness is given as a negative number so that hatchfill knows to fill with hatches. If the blue component of the `fill color' is positive, hatchfill acts just like the standard fill command. `withcolor (-10,4mm,-2pt)' draws more blue hatching, this time at -10dg, with 4mm spacing and 2pt linewidths. The second `hatchoptions()' switches to a red, dashed pen, and the second `hatchfill' draws red hatching at -30dg, with 5mm spacing and 1pt linewidths.
[edit] MetaPost, latex, pdflatex, and latex2html
If you have some MetaPost graphics (file.1, etc) you'd like to include in a .tex file, and you want the .tex file to be processable by latex, pdflatex, and latex2html, you need to have (in your .tex preamble) something like
\usepackage{html} % defines \url{}, \latex{}, \html{}, etc
\usepackage{ifpdf} % allow selection based on pdflatex or latex
\newcommand{\pdflatex}[1]{\ifpdf\latex{#1}\fi}
\usepackage{graphicx} % defines \includegraphics{mp/piezo.2}
% if pdftex doesn't recognize the type, it's mps
% usage: \DeclareGraphicsRule{ext}{type}{sizefile}{command}
\pdflatex{\DeclareGraphicsRule{*}{mps}{*}{}}
\pdflatex{some-code} is defined so {some-code} is only processed by pdflatex. The \ifpdf, \fi block tells latex to ignore {some-code}, and \latex{} tells latex2html to ignore it. \DeclareGraphicsRule tells pdflatex to treat any graphics file it doesn't recognize as an mps file.
Then in the body of the document where you want to include your image (file.1 here)
\includegraphics{file.1}
See my piezo-control note source for a compile-able example.
[edit] Embedding MetaPost code in LaTeX
You can use the emp package to include MetaPost code directly in a LaTeX document.
For example, the LaTeX file example.tex:
\documentclass{article}
\usepackage[pdftex]{graphicx}
\DeclareGraphicsRule{*}{mps}{*}{}
\usepackage{emp}
\begin{document}
\begin{empfile}[example]
\begin{emp}(4cm, 2cm)
dotlabel.rt("Hello World", origin);
\end{emp}
\end{empfile}
\end{document}
can be compiled to produce example.pdf with
$ pdflatex example.tex $ mpost -tex=latex example.mp $ pdflatex example.tex
[edit] More
We've only scratched the tip of the surface. For a more in depth tutorial with excellent examples, try this.
A script to convert mp files with embedded TeX into standalone postscripts can be downloaded here
And there is a whole wiki dedicated to metapost here



