pshacker 

Delft University of Technology 
pshacker
a Matlab
wrapper for the postscript language
January 2010
A. L. Schwab and J. P. Meijaard
PostScript is a graphic programming language developed by Adobe Systems that allows its user to produce highquality graphics and text that can be printed.
The language is somewhat hard to use because it uses this crazy Reverse Polish Notation (RPN). Therefore we wrote a Matlab wrapper around it, with identical function names as the postscript function names. These collection of Matlab functions are called 'pshacker'.
A quick and easy
introduction to postscript is 'Learning PostScript by Doing', by Andre Heck (2005):
http://staff.science.uva.nl/~heck/Courses/Mastercourse2005/tutorial.pdf
The official
postscript language reference books are the 'green book':
http://wwwcdf.fnal.gov/offline/PostScript/GREENBK.PDF
and the 'blue book' (tutorials):
http://wwwcdf.fnal.gov/offline/PostScript/BLUEBOOK.PDF
We learn by example. Read page 15 from Heck 2005.
The equivalent pshacker matlab program for EXERCISE 2 is exercise2.m:
% define a global variable which holds the postscript file identifier
global PSFID
% open the file that will contain the postsript commands
PSFID=fopen('exercise2.ps','w')
% write the header that every ps file needs
header
% write the bounding box to the file
boundingbox(5,5,105,105)
% write some shorthand notations to the file
prolog
a=10;
b=90;
newpath
moveto(a,a)
rlineto(b,0)
rlineto(0,b)
rlineto(b,0)
closepath
setlinewidth(5)
stroke
showpage
% write some closing postscript statements to the file
trailer
eof
% close the file
fclose(PSFID)
And then the postscript file exercise2.ps which exercise2.m creates looks like this:
%!PSAdobe3.0
%%BoundingBox: 5 5 105 105
%%BeginProlog
/CP /closepath load def
/CT /curveto load def
/GR /grestore load def
/GS /gsave load def
/L /lineto load def
/M /moveto load def
/NP /newpath load def
/RC /rcurveto load def
/RF /rectfill load def
/RS /rectstroke load def
/RL /rlineto load def
/RM /rmoveto load def
/RO /rotate load def
/SC /scale load def
/SF /selectfont load def
/SD /setdash load def
/SG /setgray load def
/SL /setlinewidth load def
/S /show load def
/ST /stroke load def
/TR /translate load def
/SHB {dup stringwidth pop neg exch show 0 rmoveto} def
/SHL {dup stringwidth pop neg 0 rmoveto show} def
/SHM {dup stringwidth pop 2 div neg 0 rmoveto show} def
%%EndProlog
NP
10 10 M
90 0 RL
0 90 RL
90 0 RL
CP
5 SL
ST
showpage
%%Trailer
%%EOF
The first line %! is mandatory and tells us its postscript. Next
the bounding box is defined. The prolog has a number of definitions with
shorthand notations, these make the postscipt file shorter because instead of
writing 10 10 moveto we can write
10 10 M, a silent convention is that self made
definitions are in capitols.
After the prolog we finally have our small example, the drawing of a rectangle.
Note that we have used variables a and
b in the Matlab file instead of the constants 10
and 90. This is one of the most powerful instruments you have with pshacker;
your figure is parameterized. Of course this can also be done within the
postscript language but the RPN make this and the writing of functions within
postscript very cumbersome!
An alphabetic list of the implemented postscript commands is given below. Not all postscript commands are yet implemented, but the collection below has served me well up till now. I tried to keep the postscript command and the matlab function the same, this worked for almost all commands but for a few which already existed in Matlab like fill. Here is the alphabetic overview:
arc(x,y,r,ang1,ang2)
arcn(x,y,r,ang1,ang2)
arct(x,y,r,ang1,ang2)
boundingbox(llx,lly,urx,ury)
circle(x,y,r)
closepath
comment(str)
creationdate(str)
creator(str)
curveto(x1,y1,x2,y2,x3,y3)
eof
fil
grestore
gsave
header
initclip
lineto(x,y)
moveto(x,y)
newpath
pijlpunt(xp,yp,angle,dx,dy)
pijl(x1,y1,x2,y2,dx,dy)
prolog
pstitle(str)
rcurveto(dx1,dy1,dx2,dy2,dx3,dy3)
rectclip(x,y,width,height)
rectfill(x,y,width,height)
rectstroke(x,y,width,height)
rlineto(x,y)
rmoveto(x,y)
rotate(dalfa)
scale(sx,sy)
selectfont(fontname,fontsize)
setdash(arr,offset)
setgray(x)
setlinecap(x)
setlinejoin(x)
setlinewidth(x)
setmiterlimit(x)
show(str)
showback(str)
showl(str)
showm(str)
showpage
stroke
title(str)
trailer
translate(x,y)
These files can be found in the zip file pshacker.zip. Unzip the file in a directory on your computer f.i. D:/MATLAB/user/pshacker and add this path to the Matlab path: path(path,'D:/MATLAB/user/pshacker').If you write an mfile to make a new figure don't forget to put in as one of the first lines of your code the declaration of this global variable PSFID, global PSFID.
The implementation of the commands is very straight forward, as an example I show the mfile moveto.m for the postscript command moveto:
function moveto(x,y)
global PSFID
if nargin==1
fprintf(PSFID,'%g %g M\n',x(1),x(2));
else
fprintf(PSFID,'%g %g M\n',x,y);
end
It simply makes use of the fprintf
command to write the postscript command together with the numeric data to the
file in this weird RPN. Note that you can call moveto(P) with an array P then it
assumes that the fist element P(1) holds x and the second element P(2) holds y.
I have also created some handy extra functions like f.i.
pijl(x1,y1,x2,y2,dx,dy) which draws a line with
an arrow head.
If you miss a postscript command then its very easy to add that to your
implementation.
Next I will give two examples of application, a drawing and a graph. Just run the mfile, look at the figure and then look in the mfile for the commands I used. No nice programming things, just some examples.
The first example is a drawing of a bicycle, fig1aBicycleModel.m. The resulting figure should look like this:
global PSFID
PSFID=fopen('fig1aBicycleModel.ps','w')
header
boundingbox(152,169,405,357)
pstitle('Bicycle model degrees of freedom')
creator('pshacker')
creationdate(date)
prolog
dots=0.24;
translate(200,200)
selectfont('HelveticaOblique',10)
% JBini_Benchmark2.m
scf=140;
l=scf*1.02;
Rr=scf*0.33;
Rf=scf*0.33;
lambda=pi/10;
trail=scf*0.08;
...........
The second example is a graph. The data for the graph is in the Matlab data file run19sm.mat and the mfile which generates the graph is fig3bLeanYawRateStableBicycle.m. The figure should look like this:
function fig4
global PSFID
if exist('tdleans')~=1
load run19sm.mat;
end;
PSFID=fopen('fig3bLeanYawRateStableBicycle.ps','w')
header
boundingbox(164,381,401,582)
pstitle('Stable Bicycle GB7Sv9e lean and yaw angles and rates measured and simulated')
creator('pshacker')
creationdate(date)
prolog
d=0.24;
translate(200,400)
selectfont('HelveticaOblique',8)
% b=5*40;
% h=8*18;
b=5*40;
h=8*22.5;
xmin=0;
xmax=5;
dx=xmaxxmin;
ymin=0.8;
ymax=0.8;
dy=ymaxymin;
newpath
setlinewidth(3*d)
moveto(0,h+1*d/2)
lineto(0,0)
lineto(b+1*d/2,0)
stroke
%rectstroke(0,0,b,h)
newpath
setlinewidth(1*d)
nb=5;
% gridlines
.............
Success with pshacker, I do hope you enjoy 'programming' your figures as much as we do!
Questions or comments?
a.l.schwab@tudelft.nl
(I made some extension to 2D plotting from 3D data with general projection methods. The mfiles are already in the zip file but I will discuss this some time later.)