% 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;
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;
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 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 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;
%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;
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);