\author[Sebastian Rahtz]{Sebastian Rahtz\\ Elsevier Science Ltd\\The Boulevard, Langford Lane\\Kidlington\\ Oxford, UK\\\texttt{s.rahtz@elsevier.co.uk}}\title{An introduction to PSTricks, part 4} \begin{Article} This article concludes my look at \PST{}. I hope you have enjoyed the show! The material has been drawn from a forthcoming book, entitled \emph{The \LaTeX{} Graphics Companion}, by Michel Goossens, Sebastian Rahtz and Frank Mittelbach, to be published by Addison Wesley in 1997. If you have enjoyed \BV{} articles in the last couple of years on Seminar, colour in \LaTeX, and \PST, you may find the book of interest. In this final part, we look briefly at data plotting, and then conclude with some finished examples of \PST, which are designed to show the power of the macros in unusual ways. \section{Data plotting} \PST\ has a set of high-level tools for common data-plotting functions; these can read data from external files, in a variety of formats. We will not tabulate the extra commands or graphical parameters this time, as they can be easily found in the \PST{} documentation. The simplest form of data is a set of comma or white-space delimited numbers, but values can also be enclosed in braces (\verb|{}|) or round brackets (\verb|()|). If the data is enclosed in a single set of \emph{square} brackets (\verb|[]|), and the opening \verb=[= is at the start of a line, it will be read much faster; however, it will run \TeX\ out of memory sooner. Data can also be read once, and then re-used, with the \Lcs{readdata} and \Lcs{savedata} commands. There is an important distinction between \Lcs{fileplot} or \Lcs{dataplot} which parse and validate the data in \TeX, and \Lcs{listplot}, which simply passes the data on to \PS; the latter approach means that there is no check on \PS\ memory requirements, but has the advantage that raw \PS\ can be provided to generate or manipulate the data. Just to complicate matters, use of the \Lcs{PSTtoEPS} command with the plotting commands can allow for even bigger datasets. An example of this is given below, in section~\ref{PSTprog}. It is important to realize that it is up to the user to check the data extents and scaling; \PST\ does not make the data fit a predefined plot area, unlike many other packages. Normally, judicious setting of \PKey{xunit} and \PKey{yunit} will quickly produce nice results. Axes are generated separately, and there is no provision for supplying specific labels for axis tick points. It is, on the other hand, easy to superimpose multiple plots, and use the \PS\ language to calculate functions, as the following example shows, overlaying $\sin(x)$, $\sin(x)\cos(x)$ and $\cos(x)$. \begin{example*} \begin{pspicture}(-1,-2.5)(9,2.5) \psset{xunit=.20mm,yunit=1.75cm} \psset{plotpoints=50} \psplot[linestyle=dashed,linecolor=blue] {0}{360}{x sin} \psplot[plotstyle=dots,dotstyle=triangle] {0}{360}{x cos} \psset{plotpoints=200} \psplot[linecolor=red]{0}{360} {x dup sin exch cos mul} \end{pspicture} \end{example*} The next example shows how the \Lcs{psaxes} command can be used to create graph frames; in this mode, it obeys the graphical fill and colour parameters. This picture (showing word length ($x$ axis) against occurrences ($y$ axis) in a passage of Dickens) also shows how the axis labels can be manipulated. \begin{example*} \readdata{\foo}{words.dat} \psset{yunit=.2mm,xunit=4mm} \begin{pspicture}(-2,-50)(20,250) \psaxes[axesstyle=frame,dy=50\psyunit, Dy=50,tickstyle=bottom, fillcolor=gray,fillstyle=solid](1,1)(18,229) \dataplot[plotstyle=line,linecolor=white]{\foo} \end{pspicture} \end{example*} \PST\ is not designed to be a fully-fledged business graphics package; its plotting functions are really for simple scientific plots only. However, it should be clear that the lower-level \PST\ macros, and \TeX's programmability, make it a good basis for whatever graphing is needed. We conclude this section with a crude pie chart, with the macros and some of the data used to create it; note that only segments above a certain size are labelled --- providing a sensible label for all elements would involve considerably more care. \mbox{Denis} \mbox{Girou} has written a generalised pie-chart and bar chart creation package for \PST\ (under revision at the time of writing), which can produce very professional results. \newcommand\lang[4]{% name, value, percentage, color \setcounter{thisval}{\value{lastval}} \addtocounter{thisval}{#3} \pswedge[fillcolor=#4]{1}{\thelastval}{\thethisval}% \setcounter{thishalf}{((\value{thisval}-\value{lastval})/2)+\value{lastval}} \ifnum#3>200\rput(1.3;\thethishalf){#1}\fi \setcounter{lastval}{\value{thisval}} } \bgroup\psset{unit=2.5} \centerline{\begin{pspicture}(-1.3,-1.3)(1.3,1.3) \psset{fillstyle=solid} \degrees[10000] \SpecialCoor \setcounter{lastval}{0} \lang{Romanian}{1}{3}{green} \lang{Czech}{2}{6}{blue} \lang{Bulgarian}{4}{11}{green} \lang{Japanese}{4}{11}{palegreen} \lang{Dutch}{7}{20}{black} \lang{Norwegian}{20}{56}{cyan} \lang{Greek}{26}{73}{magenta} \lang{Swedish}{34}{95}{lightgray} \lang{Danish}{46}{129}{white} \lang{French}{83}{232}{pink} \lang{Latin}{146}{409}{wheat} \lang{Russian}{243}{680}{white} \lang{Italian}{391}{1093}{gray} \lang{German}{508}{1421}{lightblue} \lang{unknown}{599}{1676}{red} \lang{English}{1462}{4085}{yellow} \end{pspicture}} \egroup \begin{sverbatim} \usepackage{calc,pstcol} \newcommand{\lang}[4]{% name, value, proportion of % 10000, colour \setcounter{thisval}{\value{lastval}} \addtocounter{thisval}{#3} \pswedge[fillcolor=#4]{1}{\thelastval}{\thethisval}% \setcounter{thishalf}{((\value{thisval}- \value{lastval})/2)+ \value{lastval}} \ifnum#3>200\rput(1.3;\thethishalf){#1}\fi \setcounter{lastval}{\value{thisval}} } \psset{fillstyle=solid} \degrees[10000] \SpecialCoor \setcounter{lastval}{0} \lang{Romanian}{1}{3}{green} \lang{Czech}{2}{6}{blue} ... \lang{German}{508}{1421}{lightblue} \lang{unknown}{599}{1676}{red} \lang{English}{1462}{4085}{yellow} \end{sverbatim} \section{\protect\PST\ programming examples}\label{PSTprog} In the following pictures, we attempt to show some of the range of \PST\ possibilities, demonstrate the advantages of using a programming language for drawing pictures, and explore the various tools for simplifying and modularizing the code to make it more readable. We are especially glad to acknowledge Denis Girou for his input to this section, both in personal exchanges and in published examples. In the first picture, a kite drawing from a child's book of colours and shapes, notice how the tail is drawn as a curved node connection between two points, and the bunting is added as labels on that connection. Use of the node feature means that the calculation of the line and positions along it are left entirely to \PST. It is also worth recalling the basic \PS\ premise that objects are opaque unless otherwise stated; this means that we can draw a blue background to the whole picture, and then overlay solid blocks of colour for the shapes. Some parts of the picture have a regular, repeating, feature, and we take advantage of this to draw the rays of sun using the \Lcs{multido} macro; note that we use a \TeX\ group to localize the effect of the \Lcs{psset} which changes colour and style. \verbfile{kite.tex} %\end{multicols} \begin{center} \vspace*{1.5ex} \input kite.tex \vspace*{1.5ex} \end{center} %\begin{multicols}{2} In the next child's picture, we again take advantage of the strikeout nature of \PS\ blocks of solid colour to draw the cat head as a whole circle, and superimpose the wall (and on top of that the bricks) so that we do not worry about creating a precise wedge of just over a semicircle. \Lcs{rput} is used extensively to place objects at an angle. The writing on the bricks demonstrates the importance of understanding the reference point of objects that are placed. Since the bricks and their legends are drawn \emph{after} the graffito, they partly obscure it. We group objects of similar characteristics together, and use \TeX's standard grouping to set \PST\ values for the items in that group. We also break the picture into different elements, describe each in a separate macro, and group them into high-level objects. This technique allows us to built up a library of objects, and serves to make the final picture description considerably more readable. The cat sitting on its portion of wall sets its size according to a parameter, allowing us to reproduce it several times at different sizes; note how the \Lcs{rput} command resets the coordinate system, so that the cat is drawn relative to the position of the \Lcs{rput}. \verbfile{cat.tex} %\end{multicols} \vspace*{1.5ex} \begin{center} \input cat.tex \end{center} \vspace*{1.5ex} %\begin{multicols}{2} The third complete picture is more complex, a circuit diagram. We have chosen to make this by programming a small language for circuit diagrams, which implements the actions \Lcs{Battery}, \Lcs{Resistor}, \Lcs{Switch} and \Lcs{Inductor}, with the movement commands \Lcs{Up}, \Lcs{Down} \Lcs{Left}, and \Lcs{Right} in the spirit of \textsf{pic}. Thus the final part of the input is quite simple, apart from the node connection and label commands which are used in their normal way (some care is needed to consider the angles at which connection lines leave and join each node). \begin{sverbatim} \Up{1} \Battery{A} \Up{1} \Right{2} \Resistor{B} \Right{1} \Down{.3} \Inductor{C} \Down{.5} \Left{1} \Switch{D} \ncangle[angleA=90,angleB=180,armB=0]{A}{B} \ncangle[angleA=0,angleB=90,armB=0]{B}{C} \ncput[ref=l]{~~~$i=i_{\mbox{max}}(1-w^{-t/3})$} \ncangle[angleA=-90,armB=0,angleB=0]{C}{D} \ncangle[angleA=180,armB=0,angleB=-90]{D}{A} \nput{180}{A}{10V} \nput{90}{B}{R} \nput{0}{C}{3mH} \nput{270}{D}{S} \end{sverbatim} \makeatletter \newdimen\CurX \newdimen\CurY \newdimen\Cir@temp \newcount\Cir@direction % 0 right, 1 left, 2 up, 3 down \Cir@direction0 \def\SetX#1{\CurX=#1pt} \def\SetY#1{\CurY=#1pt} \def\ShowDirection{\typeout{Direction: \ifcase\Cir@direction right\or left\or up\or down\fi, now at (\strip@pt\CurX,\strip@pt\CurY)}% } \def\ShowXY{\message{(\strip@pt\CurX,\strip@pt\CurY)}} \def\Down#1{\advance\CurY by -#1\p@\Cir@direction3\ShowDirection} \def\Up#1{\advance\CurY by #1\p@\Cir@direction2\ShowDirection} \def\Left#1{\advance\CurX by -#1\p@\Cir@direction1\ShowDirection} \def\Right#1{\advance\CurX by #1\p@\Cir@direction0\ShowDirection} \def\MyBox#1#2{% width,height \pssetlength{\Cir@temp}{#1}% \rule{\Cir@temp}{\z@}% \pssetlength{\Cir@temp}{#2}% \rule{\z@}{\Cir@temp}% } \def\Point#1{% \rput(\strip@pt\CurX,\strip@pt\CurY){\pnode{#1}}% } \def\Switch#1{% \message{[Switch] #1}\ShowXY \relax \ifcase\Cir@direction % right \rput[b](\strip@pt\CurX,\strip@pt\CurY){\rnode[b]{#1}{% \psline(.5,.4)% \psarc{<-}{.4}{-10}{70}% \MyBox{.5}{.4}% }}% \advance\CurX by .5\p@ \or % left \advance\CurX by -.5\p@ \rput[b](\strip@pt\CurX,\strip@pt\CurY){\rnode[b]{#1}{% \psline(0,0)(.5,.4)% \psarc{<-}{.4}{-10}{70}% \MyBox{.5}{.4}% }}% \fi } \def\Battery#1{% \message{[Battery] #1}\ShowXY \relax \ifcase\Cir@direction % right \rput[r](\strip@pt\CurX,\strip@pt\CurY){\rnode{#1}{% \psline(0,-.4)(0,.4)% \psline(.2,-.2)(.2,.2)% \MyBox{.2}{.8}% }}% \advance\CurX by .2\p@ \or % left \advance\CurX by -.2\p@ \rput[r](\strip@pt\CurX,\strip@pt\CurY){\rnode{#1}{% \psline(0,-.4)(0,.4)% \psline(.2,-.2)(.2,.2)% \MyBox{.2}{.8}% }}% \or % up \advance\CurY by .2\p@ \rput[b](\strip@pt\CurX,\strip@pt\CurY){\rnode{#1}{% \psline(.1,.2)(.9,.2)% \psline(0.3,0)(0.7,0)% \MyBox{1}{.2}% }}% \or % down \rput[b](\strip@pt\CurX,\strip@pt\CurY){\rnode{#1}{% \psline(-.4,0)(.4,0)% \psline(-.2,-.2)(.2,-.2)% \MyBox{1}{.2}% }}% \advance\CurY by -.2\p@ \fi } \def\Resistor{\message{[Resistor]}\ShowXY \@ifnextchar[{\@ResInd}{\@ResInd[1]{pszigzag}}} \def\Inductor{\message{[Inductor]}\ShowXY \@ifnextchar[{\@ResInd}{\@ResInd[1]{pscoil}}} \def\@ResInd[#1]#2#3{% \ifcase\Cir@direction % right \rput[l](\strip@pt\CurX,\strip@pt\CurY){\rnode{#3}{% \csname #2\endcsname[coilarm=.01,coilwidth=.3](0,.15)(#1,.15)% \MyBox{#1}{.3}% }}% \advance\CurX by #1\p@ \or % left \advance\CurX by -#1\p@ \rput[l](\strip@pt\CurX,\strip@pt\CurY){\rnode{#3}{% \csname #2\endcsname[coilarm=.01,coilwidth=.3](0,.15)(#1,.15)% \MyBox{#1}{.3}% }}% \or % up \rput[b](\strip@pt\CurX,\strip@pt\CurY){\rnode{#3}{% \csname #2\endcsname[coilarm=.01,coilwidth=.3](.15,0)(.15,#1)% \MyBox{.3}{#1}% }}% \advance\CurY by #1\p@ \or % down \advance\CurY by -#1\p@ \rput[b](\strip@pt\CurX,\strip@pt\CurY){\rnode{#3}{% \csname #2\endcsname[coilarm=.01,coilwidth=.3](.15,0)(.15,#1)% \MyBox{.3}{#1}% }}% \fi } \makeatother \begin{pspicture}(5,5) \SetX{1} \Up{1} \Battery{A} \Up{1} \Right{2} \Resistor{B} \Right{1} \Down{.3} \Inductor{C} \Down{.5} \Left{1} \Switch{D} \ncangle[angleA=90,angleB=180,armB=0]{A}{B} \ncangle[angleA=0,angleB=90,armB=0]{B}{C} \ncput[ref=l]{~~~$i=i_{\mbox{max}}(1-w^{-t/3})$} \ncangle[angleA=-90,armB=0,angleB=0]{C}{D} \ncangle[angleA=180,armB=0,angleB=-90]{D}{A} \nput{180}{A}{10V} \nput{90}{B}{R} \nput{0}{C}{3mH} \nput{270}{D}{S} \end{pspicture} The new commands are implemented in terms of a current $x$ and $y$ coordinate, which is changed by the movement commands. Thus \Lcs{Down} is defined (simplified) in the following code: \begin{sverbatim} \newcommand{\Down}[1]{% \setcounter{CurY}}{-#1}% \def{Cirdirection}{3}% } \end{sverbatim} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{figure*}[t!] \centerline{\includegraphics{map.eps}} \caption{Autocad picture converted to \protect\PST\ macros} \label{PSTacad} \end{figure*} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% After each movement the current direction of movement is recorded, since this affects how we draw the new objects. These have a switch (which we have simplified in the following code example\footnote{since we possibly want sizes to be real numbers, \Lcs{CurX} and \Lcs{CurY} are in fact \TeX\ dimensions, which we convert back to numbers before use.}) to check direction. The plain \TeX{} \Lcs{ifcase} command is used to perform a 4-way switch between directions. The definition of the resistor is: \begin{sverbatim} \newcommand{\Resistor}[1]{% \ifcase\Cirdirection % right \rput[l](\CurX,\CurY){\rnode{#1}{% \pszigzag[coilarm=.01,coilwidth=.3](0,.15)(1,.15)% \MyBox{1}{.3}}}% \addtocounter{CurX}{1}% \or % left \addtocounter{CurX}{-1}% \rput[l](\CurX,\CurY){\rnode{#1}{% \pszigzag[coilarm=.01,coilwidth=.3](0,.15)(1,.15)% \MyBox{1}{.3}}}% \or % up \rput[b](\CurX,\CurY){\rnode{#1}{% \pszigzag[coilarm=.01,coilwidth=.3](.15,0)(.15,1)% \MyBox{.3}{1}}}% \addtocounter{CurY}{1}% \or % down \addtocounter{CurY}{-1}% \rput[b](\CurX,\CurY){\rnode{#1}{% \pszigzag[coilarm=.01,coilwidth=.3](.15,0)(.15,1)% \MyBox{.3}{1}}}% \fi } \end{sverbatim} The macro \Lcs{MyBox} is very important; since by itself \Lcs{pszigzag} takes no space, it will create a node with no width or height, and connectors will go right to the middle. Therefore we put in some \LaTeX\ struts with the \Lcs{rule} command, to create an invisible box around the zigzag. The \PST\ units are converted to normal \TeX\ lengths using \Lcs{pssetlength}. \begin{sverbatim} \newlength{\Cirtemp} \newcommand{\MyBox}[2]{% width,height \pssetlength{\Cirtemp}{#1}% \rule{\Cirtemp}{0pt}% \pssetlength{\Cirtemp}{#2}% \rule{0pt}{\Cirtemp}% } \end{sverbatim} Our final example takes \PST\ into another subject area, that of cartography. The map in Figure~\ref{PSTacad} is created from an Autocad DXF file; this time the 36 polygons, comprising 9619 separate line segments, were converted (using a simple \emph{ad hoc} conversion program) to a separate coordinate data file for each polygon. The overall map description consists simply of 36 lines of the form: \begin{sverbatim} \ProcessVector{moh174} \ProcessVector{moh170} \end{sverbatim} Since the number of coordinates is so large, many of the \PST\ tools which can read the files (like \Lcs{fileplot}) run out of \TeX\ memory; however, for purely graphical objects like polygons, we have the more efficient and less memory-intensive option of writing Encapsulated \PS\ files on the fly, so we instantiate the \Lcs{ProcessVector} lines with the definition: \begin{sverbatim} \newcommand{\ProcessVector}[1]{% \PSTtoEPS{#1.eps}{\fileplot{#1.dat}} \rput(0,0){\includegraphics{#1.eps}}% } \end{sverbatim} The command \Lcs{PSTtoEPS} takes two arguments, a filename, and any pure \PST\ commands (\ie not text). Instead of embedding the necessary \PS\ as \Lcs{special}s in the \TeX\ output, a \PS\ file is written directly. Using the very simple top level \Lcs{ProcessVector} command means that the master file is easily hand-edited; since the Autocad file identifies the polygons by their `layer' (the map is a set of contour lines), we are able to set the fill colour separately for each layer, and so produce the more traditional map. \end{Article}