input graph.mp; warningcheck :=0; input latexmp.mp % read two columns from a file, % need to specify filename, the target % path name, and two columns, % if there's only one column, take 1---size(column) % as default x ---- well, dont' know how to do it yet now numeric n_paths; %number of paths I have read so far numeric n_line; % lines I have already plotted out numeric g_w, g_h; % global width and height of plotting area g_w=5in; g_h=4in; numeric mtfontsize, gridfontsize, lgdfontsize; mtfontsize:=14; gridfontsize:=12; lgdfontsize:=10; vardef pttoinch(expr p)=p/72 enddef; string wantgrid; numeric d[][], count[]; % d is the raw data I have seen, % p is the paths to be plotted picture line_patterns[], line_markers[]; color line_colors[]; numeric line_widths[]; % the four basic properties of each line, % needs to be remembered so that I can draw them in the legend box def rdata(expr filename)% a string % (suffix d)% an array of paths (expr column)% i is column number in the datafile = begingroup string s[]; numeric row; row:=0; gdata(filename, s, d[n_paths][row]:=Mlog_str(s[column]); row:=row+1; ); count[n_paths]:=row-1; n_paths:=n_paths+1; endgroup; enddef; % create a path from two "raw paths", which only have % meaningful x part vardef combine_paths(expr p, q)= (d[p][0],d[q][0]) for i=1 upto min(count[p], count[q]): -- (d[p][i],d[q][i]) endfor enddef; input string.mp % style specification: % the first two are column numbers, % then following are specifications % seperated by whitespace, % the "linewdith" number should be preceded by % "linewidth" , color is started by "c", pattern is started by % "p" % add a one line from existing data repository into % the set of paths to be printed, p. also parse the % line style, etc. def mtplot(expr cmd)= begingroup numeric x,y; string style; path p; string ss; numeric marker_idx; ss:=cmd; % now use default setting if not specified line_widths[n_line]:=1; line_patterns[n_line] := patterns[n_line mod (patterns.count+1)].d; line_colors[n_line] := colors[n_line mod ( colors.count+1)].d; marker_idx := 0; % X and Y column index x := scantokens(loptok ss ); y := scantokens(loptok ss ); p := combine_paths(x,y); forever : exitif ss=""; style := loptok(ss); if ( style = "linewidth" ) : line_widths[n_line]:= scantokens( loptok(ss)); else : if ( (substring(0,1) of style) = "c" ): line_colors[n_line]:=searchdefault.colors(style); else: if ( ( substring(0,1) of style ) = "p" ): line_patterns[n_line]:= searchdefault.patterns(style); else: if ( ( substring(0,1) of style ) = "m" ): marker_idx := searchdefault.markers(style); fi % t spec fi % p spec fi% color spec fi % width spec endfor; line_markers[n_line]:=markersp(marker_idx, withpen pencircle scaled line_widths[n_line] withcolor line_colors[n_line] ); gdraw p withpen pencircle scaled line_widths[n_line] withcolor line_colors[n_line] dashed line_patterns[n_line] scaled line_widths[n_line] % scaled is important, so width and length of dashes are % proportional ; gdraw p plot line_markers[n_line]; n_line := n_line+1; endgroup; enddef; vardef ttt primary a = (1=1) enddef; %search color or pattern from default table vardef searchdefault@#(expr query)= %take the substring from the second char upward string sss; sss:=( substring (1,cspan(query,ttt)) of query); searchdefault_rec@#(0,sss) enddef; % a recursive definition vardef searchdefault_rec@#(expr idx, query )= if ( @#[idx].name = query ): @#[idx].d elseif ( idx = @#.count): @#[0].d % at the last choice, have to use it else: searchdefault_rec@#(idx+1, query) fi enddef; %default color table string colors[].name; color colors[].d; numeric colors.count; colors[0].name:="k"; colors[0].d:=black; colors[1].name:="r"; colors[1].d:=red; colors[2].name:="g"; colors[2].d:=green; colors[3].name:="b"; colors[3].d:=blue; colors[4].name:="y"; colors[4].d:=red+green; colors[5].name:="o"; colors[5].d:=1.5*red+ 0.5*green; colors[6].name:="p"; colors[6].d:=red+blue; colors.count:=6; %default dash patterns string patterns[].name; picture patterns[].d; numeric patterns.count; patterns[0].name:="solid"; patterns[0].d:=nullpicture; patterns[1].name:="dash"; patterns[1].d:=evenly; patterns[2].name:="dot"; patterns[2].d:=dashpattern( on 0 off 1.5 ); patterns[3].name:="dashdot"; patterns[3].d:=dashpattern(on 4 off 2 on 1 off 2) ; patterns[4].name:="dddash"; patterns[4].d:=dashpattern(on 1 off 2 on 1 off 2 on 4 off 2); patterns[5].name:="dddot"; patterns[5].d:=dashpattern( on 4 off 2 on 4 off 2 on 1 off 2 ); patterns.count:=5; %default markers string markers[].name; numeric markers[].d; numeric markers.count; picture temppic; markers[0].name:="o"; markers[1].name:="x"; markers[2].name:="*"; markers[3].name:="d"; markers[4].name:="s"; % just to make the function "searchdefault()" return the index markers[0].d:=0; markers[1].d:=1; markers[2].d:=2; markers[3].d:=3; markers[4].d:=4; markers.count=4; numeric markersize; markersize:=3bp; % a wacky trick to paste the options % (withpen, etc) that is to be supplied later onto % the marker picture % markers_picture or "markers_paths" def markeritem(text s)= hide( % save tmp_pic; picture tmp_pic; tmp_pic:=nullpicture; s; ) tmp_pic enddef; def markerset(text opt)= markeritem( trash:=1; ), %nothing markeritem( % "X" addto tmp_pic doublepath ( (-1,-1) -- (1, 1) ) scaled markersize opt; addto tmp_pic doublepath ( (-1, 1) -- (1,-1) ) scaled markersize opt; ) , markeritem( % "*" for i=1, 2 , 3: addto tmp_pic doublepath ( dir(i*120) -- dir(i*120+180) ) scaled markersize opt; endfor; ), markeritem( % diamond "d" addto tmp_pic doublepath unitsquare shifted (-.5, -.5) rotated 45 scaled markersize opt; ), markeritem( % square "s" addto tmp_pic doublepath unitsquare shifted ( -.5 , -.5) opt; ) enddef; def markersp(expr idx)(text opt)= hide ( numeric i; picture result,j; i:=0; for j=markerset(opt): % list out all possible markers if ( i=idx): result:=j; fi i:=i+1; endfor if ( unknown result ): result:=j; % just last marker fi ) result enddef; def xlabel(expr l)= glabel.bot(textext("{\mtfont " & l & " } ") , OUT ); enddef; def ylabel(expr l)= glabel.lft(textext("{\mtfont " & l & " } ") rotated 90, OUT); enddef; %draw the legend, do calculation on the legend box size % need lgdfontsize, how many lines to draw, etc, % also use the remembered line properties vardef legend(expr x, y)(text tags)= numeric lgd_w, lgd_h, lgd_x, lgd_y; % size of legend box picture lgd, tmp_lgd; string s,tagstr[]; numeric i,j; % parse the tags first, put them into an array, i:=0; for s=tags: tagstr[i]:=s; i:=i+1; endfor for j=i upto n_line -1: tagstr[i]:=decimal(j); endfor tmp_lgd:=nullpicture; lgd:=nullpicture; %first draw the legend box into picture, then % draw it and shift it margin:=(lgdfontsize/2); for i = 0 upto n_line -1: % draw the sample line in legend box addto tmp_lgd doublepath (( (0,0) -- ((g_w /10),0)) shifted ( margin , 2margin+ lgdfontsize *i*1.5 ) ) withpen pencircle scaled line_widths[i] withcolor line_colors[i] dashed line_patterns[i] scaled line_widths[i]; % add anotation to the sample line addto tmp_lgd also thelabel.rt( textext("{\lgdfont "& tagstr[i] & "}"), ( (margin+g_w/10+margin) ,(2margin+ lgdfontsize *i*1.5)) ); % draw marker mark on sample line addto tmp_lgd also line_markers[i] shifted ( ((g_w/20),0) + ( (margin), (2margin+ lgdfontsize *i*1.5)) ); endfor; path box; box:=bbox(tmp_lgd); lgd_w:= xpart(point 1 of box) + margin; lgd_h:= n_line * lgdfontsize *1.5 + 2margin; addto lgd contour (0,0)--(lgd_w,0)--(lgd_w,lgd_h)--(0,lgd_h)--cycle withcolor .95 white; % fill the background of legend box with white addto lgd doublepath (0,0)--(lgd_w,0)--(lgd_w,lgd_h)--(0,lgd_h)--cycle withpen pencircle; addto lgd also tmp_lgd; % now calculate position of legend box if ( x = 1 ): lgd_x := (g_w/20); elseif( x= 2): lgd_x:=(g_w/2-(lgd_w)/2); else: lgd_x:=(g_w*19/20) - lgd_w; fi if ( y=1): lgd_y:=(g_h/10); elseif (y=2): lgd_y:=(g_h/2-(lgd_h)/2); else: lgd_y:=(g_h*9/10)- lgd_h; fi %finally draw the legend box draw lgd shifted (lgd_x, lgd_y); enddef; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% defaultfont:="Helvetica"; % initialization def begingrf(expr w, h)= hide( string tempstr; tempstr:= "\font\mtfont=" & defaultfont & " at " & decimal(mtfontsize) &"pt " & " \font\lgdfont=" & defaultfont & " at " &decimal(lgdfontsize) & "pt " & " \font\gridfont=" & defaultfont & " at " &decimal(gridfontsize) &"pt " ; %legend font, use normal 10pt setupLaTeXMP(preamble=tempstr); ) begingraph(w,h); init_numbers(btex$-$etex, textext("{\gridfont 1}"), %btex$1$etex, btex ${\times}10$ etex, btex${}^-$etex, btex${}^2$etex); Gtemplate.itick := origin -- (w/100,0); Gtemplate.otick := origin -- (-w/100,0); interim Gpaths:=log; n_line:=0; n_paths:=0; wantgrid:="yes"; enddef; % plot out everyting else def finishgrf = autogrid(itick.bot,itick.lft) withpen pencircle scaled 1.5; if ( wantgrid = "yes" ): autogrid(grid.bot,grid.lft) withpen pencircle scaled 0.5 dashed evenly; fi frame withpen pencircle scaled 1; endgraph; enddef;