%! %%BoundingBox: 126 246 486 546 % Cookbook Example Program from First Printing, Revised 7 Jan 1985 % Program: Drawing a Pie Chart Number: 18 %----------------------------------------------------------------------------- % /PieDict 24 dict def % Local storage for % ``DrawPieChart'' and its related % procedures. PieDict begin /DrawSlice % DrawSlice draws an outlined and { /grayshade exch def % filled-in pie slice. It takes /endangle exch def % four operands: the label for /startangle exch def % this particular pie slice, the /thelabel exch def % starting angle for the slice, % the ending angle for the slice % and the shade of gray the slice % should be. newpath % Create a path which will draw a % pie slice. 0 0 moveto 0 0 radius startangle endangle arc closepath 1.415 setmiterlimit % This guarantees that when we % outline the pie slices with a % stroke that we will not get a % spike on the interior angles. gsave grayshade setgray fill grestore % Fill the pie slice path with the stroke % appropriate gray color. By using % gsave and grestore we don't lose % the current path. Since % PostScript paints color onto the % page, it is very important that % we fill the pie slice first and % then outline it with a stroke. gsave % Draw the tick mark and place the % label: startangle endangle add 2 div % Find the center of the pie slice rotate % and rotate so that the x-axis % coincides with this center. radius 0 translate % Translate the origin out to the % circumference. newpath 0 0 moveto labelps .8 mul 0 lineto% Draw the tick-mark. stroke labelps 0 translate % Move the origin out a little % beyond the circumference. 0 0 transform % Next we wish to place the label grestore % at the current origin. If we itransform % simply draw the text on the page /y exch def /x exch def % now, it would come out rotated. x y moveto % Since this is not desired we % avoid it by returning to the % previous unrotated coordinate % system. Before returning, % though, we would like to x 0 lt % remember the position of the { thelabel stringwidth pop neg % current origin on the printed 0 rmoveto % page. We will accomplish this by } if % using the transform and % itransform operators. Performing % a transform on the origin pushes % the coordinates of the origin in % device space onto the operand % stack. Performing a grestore % returns us to the previous % unrotated coordinate system. % Next we perform an itransform on % the two device coordinates left % on the stack to determine where % we are in the current coordinate % system. y 0 lt { 0 labelps neg rmoveto } if % Make some adjustments so that thelabel show % the label text won't collide } def % with the pie slice. /findgray % Procedure findgray calculates { /i exch def /n exch def % the gray value for a slice. It i 2 mod 0 eq % takes two arguments: the total { i 2 div n 2 div round add n div } % number of slices and the current { i 1 add 2 div n div } % slice number (Given that there ifelse % are n pie slices, the slices are } def % ``numbered'' from 1 to n). The end % gray values for the pie slices % range evenly from white to black % (i.e. - the values provided to % setgray range from (n/n, n-1/n, % ..., 1/n)). Since we don't want % similar values of gray next to % each other, findgray % ``shuffles'' the possible % combinations of gray. /DrawPieChart % DrawPieChart takes seven { PieDict begin % arguments: the title of the pie /radius exch def % chart, the point size to print /ycenter exch def /xcenter exch def % the title in, the point size to /PieArray exch def % print the labels for each slice /labelps exch def /titleps exch def % in, a special array (described /title exch def % below where DrawPieChart is % called), the (x,y) center of the % pie chart and the radius of the % pie chart. gsave xcenter ycenter translate % Translate the coordinate system % origin to center of pie chart. /Helvetica findfont titleps % Print the title of the pie chart scalefont setfont % in Helvetica. title stringwidth pop 2 div neg % Center the title below the pie % chart. radius neg titleps 3 mul sub moveto title show /Helvetica findfont labelps % Print the individual pie slice scalefont setfont % labels in Helvetica /numslices PieArray length def /slicecnt 0 def /curangle 0 def % A ``loop'' variable that keeps % track of the angle of arc to % begin each pie slice at. PieArray % Repeat the following for each % element in the PieArray. { /slicearray exch def slicearray aload pop % Push the label and percentage % onto the stack. /percent exch def /label exch def /perangle percent 360 mul def % Convert the percentage into % degrees of angle. /slicecnt slicecnt 1 add def label curangle curangle perangle add numslices slicecnt findgray DrawSlice /curangle curangle perangle add % Update the current starting % angle. def } forall grestore end } def () 18 9 [ [(Blueberry) .12 ] % The pie array is an array of [(Cherry) .30 ] % arrays. Each array in the pie [(Apple) .26 ] % array contains a string denoting [(Boston Cream) .16 ] % the label to be printed next to [(Other) .04 ] % the pie slice followed by a real [(Vanilla Cream) .12 ] % number indicating the percentage ] 306 396 100 DrawPieChart % of the pie represented by this % particular slice. showpage