(**************************************************************************) (* This program simulates a graph environment for LaTeX. Using a list of *) (* parameters, it generates LaTeX commands to produce a complete graph. *) (* see the latexgraph.doc file for detailed documentation. *) (* author:Sunil Podar, podar@sbcs.csnet, ...!{allegra,philabs}!sbcs!podar *) (* Please quote the following date when sending bug reports. *) (* last update: Feb 2, 1987 (fixed bugs: wasn't doings things right when *) (* (0,0) was not on the graph. Also removed the printing of *) (* a few of the margin commands from preamble. *) (* last update: Oct 5, 1986 *) (**************************************************************************) program main (input,output); const delim = '@'; (* Latex never uses @ except for \@ for a little *) (* space before a sentence-ending period *) maxchar = 'F';(* maximum types of characters permitted for plotchar*) (* A..F i.e. 6 distinct chars permitted *) type wholeline = packed array[1..80] of char; tenchar = packed array[1..10] of char; ninechar = packed array[1..9] of char; twochar = packed array[1..2] of char; plotstufftype = record chardef : wholeline; charname : wholeline end; var plotstuff : array['A'..maxchar] of plotstufftype; error1,itsreal :boolean; picwd,picht,pos,Xdeltabar, Ydeltabar,i,Xlegloc,Ylegloc,Xdeltanum,Ydeltanum : integer; Xaxisstrg,Yaxisstrg,capstring,blank80,labelname,fontname : wholeline; legendloc,captiontwo,prepost : twochar; string,blank10,captiontype,fignumber : tenchar; plotchar,c : char; string9 : ninechar; Xscalegraph,Yscalegraph : integer; XGorig,YGorig,XP1orig,YP1orig,XP2orig,YP2orig : integer; Xscalereal,Yscalereal,xreality, yreality, xgraph, ygraph, unitlngth,textwd,Xorignum,Yorignum,deln,num : real; procedure strreadline(var commandstr: wholeline); var charac:char; i : integer; endoffile, endofline:boolean; begin i:=1; endoffile :=false; endofline:=false; commandstr:=blank80; repeat read(charac); if (i < 80) then commandstr[i] := charac; (* 80th char remains @ *) i := i+1; if eof then endoffile :=true else if eoln then endofline :=true until (endoffile or endofline); if (i <= 80) then commandstr[i] := delim; if not endoffile then readln end; (*strreadline*) procedure strreadword(var string: tenchar; var string9: ninechar); var charac:char; i : integer; begin i:=1; string:=blank10; read(charac); repeat string[i] := charac; read(charac); i := i+1 until ((charac = '/') or (charac = ' ') or (i > 10) or eoln); (* so I'm reading the / without assigning it to string, neat *) if (eoln and (i <=10)) then string[i]:= charac; (* a kluge, to capture the last charac when using this procedure to *) (* read the argument. normally I use it only for parameters. *) for i:= 1 to 9 do string9[i] := string[i] end; (*strreadword*) procedure strwrite(str: wholeline); var i : integer; begin i := 1; while (str[i] <> delim) do begin write(str[i]); i := i+1 end end; procedure legendread; var i : integer; temp : twochar; begin temp := ' '; legendloc := ' '; i := 0; if (not eoln) then repeat i := i+1; read(legendloc[i]); until (eoln) or (i >= 2) or (legendloc[i] = '/'); if (not eoln) then if (legendloc[i] <> '/') then read(temp[1]); if (temp[1] = '/') or (legendloc[i] = '/') then readln(Xlegloc,Ylegloc) else readln end; (* legendread *) (* in the following procedures, the boolean var XorY: true => X & false => Y*) procedure putbars(XorY:boolean; Xpos, Ypos, deltabar, distance: integer); var times: integer; begin times := distance div abs(deltabar); if times > 0 then if XorY (* X *) then writeln('\multiput(',Xpos:1,',',Ypos:1,')(', deltabar:1,',0){',times:1,'}{\line(0,1){2}}') else writeln('\multiput(',Xpos:1,',',Ypos:1,')(0,', deltabar:1,'){',times:1,'}{\line(1,0){2}}'); end; (* putbars *) (* see a note about putnumbers in the main program. *) (* because we may have real numbers, we can't use a counter *) (* in conjunction with a \multiput statement. *) procedure putnumbers(XorY:boolean; fixedpos, initpos:integer; initnum, deln:real; deltanum:integer; limit:real); var pos: integer; num: real; begin num:=initnum; pos:= initpos; if (abs(num) - round(abs(num) - 0.5)) > 0 then itsreal := true; while abs(pos) < abs(limit) do begin if XorY then (* X *) write('\put(',pos:1,',',fixedpos:1,'){\makebox(0,0)[t]{') else write('\put(',fixedpos:1,',',pos:1,'){\makebox(0,0)[r]{'); if itsreal then writeln(num:1:2,'}}') else writeln(trunc(num):1,'}}'); pos := pos + deltanum; num := num + deln end; end; (* putnumbers *) begin(* main *) (*----------------------------------*) (* Initializations & default values *) (*----------------------------------*) error1 := false; itsreal:=false; for i := 1 to 10 do blank10[i] := ' '; for i := 1 to 79 do blank80[i] := ' '; blank80[80] := delim; captiontype := blank10; captiontype := 'no '; (*default 'no' *) fignumber := blank10; fontname := blank80; (* just playing it safe *) fontname := '{normalsize}'; fontname[13] := delim; labelname := blank80; labelname[1] := 'n'; (* default 'no' *) prepost := 'no'; unitlngth := 1.0; picwd := 100; picht := 100; XP1orig := 0; YP1orig := 0; legendloc := 'no'; Xscalegraph := 10; Xscalereal := 10; Yscalegraph := 10; Yscalereal := 10; Xdeltabar := 5; Xdeltanum := 10; Ydeltabar := 5; Ydeltanum := 10; Xorignum := 0; Yorignum := 0; for c := 'A' to maxchar do begin plotstuff[c].chardef[1] := 'n'; (* default value is 'no' *) plotstuff[c].charname := blank80; plotstuff[c].charname[1] := c; plotstuff[c].charname[2] := delim end; Xlegloc := -999999; Ylegloc := -999999; strreadword(string, string9); while string <> '%%%%%%%%%%' do begin if string = '%pre&post?' then readln(prepost[1]) else if string = '%unitlngth' then readln(unitlngth) else if string = '%font-name' then strreadline(fontname) else if string = '%picdimens' then readln(picwd,picht,XP1orig,YP1orig) else if string = '%??caption' then begin strreadword(captiontype, string9); readln end else if string = '%fignumber' then begin strreadword(fignumber, string9); readln end else if string = '%Xaxisstrg' then strreadline(Xaxisstrg) else if string = '%Yaxisstrg' then strreadline(Yaxisstrg) else if string = '%capstring' then strreadline(capstring) else if string = '%labelname' then strreadline(labelname) else if string = '%legendloc' then legendread else if string = '%Xdeltab:n' then readln(Xdeltabar,Xdeltanum) else if string = '%Xoriginum' then readln(Xorignum) else if string = '%Ydeltab:n' then readln(Ydeltabar,Ydeltanum) else if string = '%Yoriginum' then readln(Yorignum) else if string = '%Xratiog:r' then readln(Xscalegraph,Xscalereal) else if string = '%Yratiog:r' then readln(Yscalegraph,Yscalereal) else if string9 = '%plotchar' then strreadline(plotstuff[string[10]].chardef) else if string9 = '%plotname' then strreadline(plotstuff[string[10]].charname) else begin readln;writeln; writeln('**********************************************'); writeln('error: unknown string: "',string,'"'); writeln('**********************************************'); error1:=true end; string := blank10; strreadword(string, string9) end; (* while *) readln; (* this readln is to finish reading the %%%%%.. line*) (* THE FUN BEGINS HERE *) if not error1 then begin textwd := picwd*unitlngth + 15.0; (* in mm *) if (textwd < 170) then textwd := 170; if textwd >240 then begin writeln('% *****************************************************'); writeln('% max-possible-picwd is about 240mm which will have '); writeln('% to be in Landscape. You''ll have to reduce scales.'); writeln('% *****************************************************') end else if textwd > 170 then begin writeln('% *****************************************************'); writeln('% THIS TEXT IS A BIT TOO WIDE FOR VERTICAL PAPER MODE.'); writeln('% YOU WILL HAVE TO USE LANDSCAPE MODE TO PRINT.'); writeln('% *****************************************************') end; if prepost[1] = 'y' then begin writeln('\documentstyle{article}'); writeln('\setlength{\textwidth}{',textwd:1:2,'mm}'); writeln('\pagestyle{empty} % => no page number '); writeln('\begin{document}'); writeln; end; (* end prepost *) write('\newcommand{\xaxis}{'); strwrite(Xaxisstrg); writeln('} % the literal for X-axis'); write('\newcommand{\yaxis}{'); strwrite(Yaxisstrg); writeln('} % the literal for Y-axis'); c := 'A'; while (plotstuff[c].chardef[1] <> 'n') and (c <= maxchar) do begin write('\newcommand{\pchar',c,'}'); strwrite(plotstuff[c].chardef); writeln; c := chr(ord(c) + 1) end; writeln; write('\begin'); strwrite(fontname); writeln; (* fontname contains braces*) writeln('\begin{figure}[p] %you might want different options here'); (* XGorig & YGorig refer to the origin of the graph. *) (* XP1orig & YP1orig refer to the bottom-left origin of the picture box.*) (* XP2orig & YP2orig refer to the bottom-right corner of the picture box.*) (* see if (0,0) is on the graph or not *) XGorig := 0; YGorig := 0; if XP1orig >= 0 then XGorig := XP1orig else if (picwd + XP1orig) < 0 then XGorig := XP1orig + picwd; if YP1orig >= 0 then YGorig := YP1orig else if (picht + YP1orig) < 0 then YGorig := YP1orig + picht; XP2orig := picwd + XP1orig; YP2orig := picht + YP1orig; writeln('\unitlength = ',unitlngth:1:2,'mm'); writeln('\begin{center}'); writeln('\begin{picture}(',(picwd+10):1,',',(picht+10):1,')(', (XP1orig-5):1,',',(YP1orig-5):1,')'); (* need a box of +10 on both axes to account for -10 origins & to *) (* get proper centering *) writeln('\thicklines'); (* plot the horizontal axis *) if (XP2orig - XGorig) > 0 then begin writeln('\put(',XGorig:1,',',YGorig:1,'){\vector(1,0){', abs(XP2orig-XGorig):1,'}}'); writeln('\put(',(XP2orig+2):1,',',YGorig:1,'){\makebox(0,0)[l]{X}}') end; if (XGorig - XP1orig) > 0 then begin writeln('\put(',XGorig:1,',',YGorig:1,'){\vector(-1,0){', abs(XGorig-XP1orig):1,'}}'); writeln('\put(',(XP1orig-2):1,',',YGorig:1, '){\makebox(0,0)[r]{X}}') end; (* plot the vertical axis *) if (YP2orig - YGorig) > 0 then begin writeln('\put(',XGorig:1,',',YGorig:1,'){\vector(0,1){', abs(YP2orig-YGorig):1,'}}'); writeln('\put(',XGorig:1,',',(YP2orig+2):1,'){\makebox(0,0)[b]{Y}}') end; if (YGorig - YP1orig) > 0 then begin writeln('\put(',XGorig:1,',',YGorig:1,'){\vector(0,-1){', abs(YGorig-YP1orig):1,'}}'); writeln('\put(',XGorig:1,',',(YP1orig-2):1, '){\makebox(0,0)[t]{Y}}') end; writeln('\thinlines'); (*********************************************************************) (*the following put numbers & bars along X-axis and Y-axis *) (*********************************************************************) putbars(true,XGorig,(YGorig-1),Xdeltabar,abs(XP2orig-XGorig)); putbars(true,XGorig,(YGorig-1),-Xdeltabar,abs(XGorig-XP1orig)); putbars(false,(XGorig-1),YGorig,Ydeltabar,abs(YP2orig-YGorig)); putbars(false,(XGorig-1),YGorig,-Ydeltabar,abs(YGorig-YP1orig)); (* Before invoking putnumbers, we must explicitly check if it needs to be invoked at all. This is because in the procedure putnumbers I use absolute values as the stopping condition for while loop. We use absolute values in the procedure so as to handle plotting numbers on both the positive and negative halves of the axes. deln below represents the delta graph units corresponding to X|Ydeltanum. *) writeln('% Add a line similar to next one if number at origin desired.'); deln := (Xscalereal*Xdeltanum) / Xscalegraph; pos := XGorig + Xdeltanum; num:=Xorignum + deln; if pos < XP2orig then putnumbers(true,(YGorig-2),pos,num,deln,Xdeltanum,XP2orig); pos := XGorig - Xdeltanum; num:=Xorignum - deln; if pos > XP1orig then putnumbers(true,(YGorig-2),pos,num,-deln,-Xdeltanum,XP1orig); deln := ( Yscalereal*Ydeltanum) / Yscalegraph; pos := YGorig + Ydeltanum; num:=Yorignum + deln; if pos < YP2orig then putnumbers(false,(XGorig-2),pos,num,deln,Ydeltanum,YP2orig); pos := YGorig - Ydeltanum; num:=Yorignum - deln; if pos > YP1orig then putnumbers(false,(XGorig-2),pos,num,-deln,-Ydeltanum,YP1orig); (***********************) (* put the legend box *) (***********************) if (legendloc <> 'no') then begin (* and if it is then obviously do nothing *) if (Xlegloc = -999999) and (Ylegloc = -999999) then begin (* implies explicit coordinates not specified *) (* if they are then they are set in legendread *) Xlegloc := picwd div 2; (* default is center *) Ylegloc := picht div 2; (* default is center *) if (legendloc[1] = 't') or (legendloc[2] = 't') then if YP2orig > 0 then Ylegloc := picht else Ylegloc := picht-10; if (legendloc[1] = 'b') or (legendloc[2] = 'b') then if YP1orig >= 0 then Ylegloc := 10 else Ylegloc := 0; if (legendloc[1] = 'l') or (legendloc[2] = 'l') then if XP1orig >= 0 then Xlegloc := 10 else Xlegloc := 0; if (legendloc[1] = 'r') or (legendloc[2] = 'r') then if XP2orig > 0 then Xlegloc := picwd else Xlegloc := picwd-10; Xlegloc := Xlegloc + XP1orig; Ylegloc := Ylegloc + YP1orig end; write('\put(',Xlegloc:1,',',Ylegloc:1,'){\makebox(0,0)'); i:= 1; write('['); while (i <= 2) do begin if (legendloc[i] <> ' ') and (legendloc[i] <> '/') then write(legendloc[i]); i:=i+1 end; write(']'); writeln('{\fbox{\shortstack[l]{'); c:='A'; while (plotstuff[c].chardef[1] <> 'n') and (c <= maxchar) do begin write(' {\makebox(4,2)[lb]{\put(2,1){\pchar',c,'}}}: '); strwrite(plotstuff[c].charname); writeln('\\'); c := chr(ord(c) + 1) end; writeln(' {\makebox(4,4)[b]{X}}: \xaxis \\'); writeln(' {\makebox(4,2)[b]{Y}}: \yaxis'); writeln(' }}}}') end; (* not 'no' of legendloc*) (* put the caption if explicit *) captiontwo[1]:=capstring[1]; captiontwo[2]:=capstring[2]; if captiontype[1] = 'e' then (* "e"xplicit, anything else other than *) (* "L" for LaTeX => no *) if captiontwo = 'YX' then begin writeln('% if the caption line is longer than the graphwidth, comment'); writeln('% out the second line and use first one. you might have to'); writeln('% fiddle with the width of parbox in the second stmt.'); write('%\put(',XP1orig:1,',',(YP1orig-18):1, '){\makebox(',picwd:1,',0)[tl]{'); writeln('Figure ',fignumber,'$\!$: \parbox[t]{',(textwd-32):1:1,'mm}{%'); write('\put(',XP1orig:1,',',(YP1orig-18):1, '){\makebox(',picwd:1,',0)[t]{'); writeln('Figure ',fignumber,'$\!$: {%'); writeln('%\yaxis\ vs.\ \xaxis}}}') end else (* means explicit string is specified *) begin write('%\put(',XP1orig:1,',',(YP1orig-18):1, '){\makebox(',picwd:1,',0)[tl]{'); writeln('Figure ',fignumber,'$\!$: \parbox[t]{',(textwd-32):1:1,'mm}{%'); write('\put(',XP1orig:1,',',(YP1orig-18):1, '){\makebox(',picwd:1,',0)[t]{'); writeln('Figure ',fignumber,'$\!$: {%'); strwrite(capstring); writeln; writeln('}}}'); end; writeln('% beginning of data'); while not eof do begin readln(plotchar,xreality,yreality); xgraph := (xreality*Xscalegraph)/Xscalereal; ygraph := (yreality*Yscalegraph)/Yscalereal; writeln('\put(',xgraph:1:5,',',ygraph:1:5,'){\pchar',plotchar,'}') end; writeln('% end of data'); writeln('\end{picture}'); writeln('\end{center}'); (* put the LaTeX \caption if so specified *) if captiontype[1] = 'L' then (* "L"aTeX . if it is not = 'L' or 'e'*) (* then interpreted as 'no' *) begin writeln('% if the caption line is longer than the graphwidth,use a'); writeln('% \parbox[t]{...mm}{.......} like statement for the argument'); writeln('% with suitable args for parbox to get things centered.'); if captiontwo = 'YX' then begin writeln('% You might want to add a [] to \caption below.'); writeln('\caption{\protect\normalsize \yaxis\ vs.\ \xaxis }') end else begin writeln('\caption{\protect\normalsize '); strwrite(capstring); writeln; writeln('}') end; if labelname[1] = '{' then (* anything else => 'no' *) begin write('\label'); strwrite(labelname); writeln (* labelname contains the braces *) end end; writeln('\end{figure}'); writeln; (* a blank line is supposedly needed before \end fontname *) (* so says the latex manual *) write('\end'); strwrite(fontname); writeln; (* fontname contains braces *) writeln; if prepost[1] = 'y' then writeln('\end{document}'); end (* not error1 *) end.