diff options
Diffstat (limited to 'metapost')
-rw-r--r-- | metapost/context/base/mp-grap.mpiv | 929 |
1 files changed, 487 insertions, 442 deletions
diff --git a/metapost/context/base/mp-grap.mpiv b/metapost/context/base/mp-grap.mpiv index 1c7a50124..34b1bd1cc 100644 --- a/metapost/context/base/mp-grap.mpiv +++ b/metapost/context/base/mp-grap.mpiv @@ -24,7 +24,7 @@ fi %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% $Id: graph.mp,v 1.2 2004/09/19 21:47:10 karl Exp $ +% $Id : graph.mp,v 1.2 2004/09/19 21 :47 :10 karl Exp $ % Public domain. % Macros for drawing graphs @@ -39,10 +39,10 @@ fi % glabel<suffix>(pic,loc) place label pic near graph coords or time loc % gdotlabel<suffix>(pic,loc) same with dot % OUT loc value for labels relative to whole graph -% gdata(file,s,text) read coords from file; evaluate t w/ tokens s[] +% gdata(file,s,text) read coords from file ; evaluate t w/ tokens s[] % auto.<x or y> default x or y tick locations (for interation) % itick.<bot|top|..>(fmt,u) draw inward tick from given side at u w/ format -% otick.<bot|top|..>(fmt,u) draw outward tick at coord u; label format fmt +% otick.<bot|top|..>(fmt,u) draw outward tick at coord u ; label format fmt % grid.<bot|top|..>(fmt,u) draw grid line at u with given side labeled % autogrid([itick|.. bot|..],..) iterate over auto.x, auto.y, drawing tick/grids % frame.[bot|top..] draw frame (or one side of the frame) @@ -61,9 +61,9 @@ fi % Other than the above-documented user interface, all externally visible names % are of the form X_.<suffix>, Y_.<suffix>, or Z_.<suffix>, or they start -% with `graph_' (was: "`G' and end with `_'"). +% with `graph_' -% Depends on: +% Depends on : input string.mp % Private version of a few marith macros, fixed for double math... @@ -71,106 +71,112 @@ newinternal mzero ; mzero := -53*mlog 2 ; % Anything at least this small is tr newinternal mlogten ; mlogten := mlog(10) ; % Would this be better inline? % Safely convert a number to mlog form -vardef graph_mlog primary x = if x=0 : mzero else : mlog(abs x) fi enddef; +vardef graph_mlog primary x = + if unknown x : whatever + elseif x=0 : mzero + else : mlog(abs x) + fi +enddef ; % Convert x from mlog form into a pair whose xpart gives a mantissa and whose % ypart gives a power of ten. vardef graph_Meform(expr x) = - if x<=mzero: origin - else: - save e; e=round(x/mlogten)-3; - (mexp(x-e*mlogten), e) + if x<=mzero : origin + else : + save e, m ; e=floor(x/mlogten)-3; m := mexp(x-e*mlogten) ; + if abs m<1000 : m := m*10 ; e := e-1 ; elseif abs m>=10000 : m := m/10 ; e := e+1 ; fi + (m, e) fi -enddef; +enddef ; % Modified from above. vardef graph_Feform(expr x) = - interim warningcheck:=0; - if x=0: origin - else: - save e; e=round(if x<0: -mlog(-x) else: mlog(x) fi/mlogten)-3; - (x/(10**e), e) + interim warningcheck :=0 ; + if x=0 : origin + else : + save e, m ; e=floor(if x<0 : -mlog(-x) else : mlog(x) fi/mlogten)-3; m := x/(10**e) ; + if abs m<1000 : m := m*10 ; e := e-1 ; elseif abs m>=10000 : m := m/10 ; e := e+1 ; fi + (m, e) fi -enddef; +enddef ; vardef graph_error(expr x,s) = - interim showstopping:=0; - show x; errmessage s; -enddef; + interim showstopping :=0 ; + show x ; errmessage s; +enddef ; %%%%%%%%%%%%%%%%%%%%%%%% Data structures, begingraph %%%%%%%%%%%%%%%%%%%%%%%% -vardef Z_@# = (X_@#,Y_@#) enddef; % used in place of plain.mp's z convention +vardef Z_@# = (X_@#,Y_@#) enddef ; % used in place of plain.mp's z convention def graph_suffix(suffix $) = % convert from x or y to X_ or Y_ - if str$="x": X_ else: Y_ fi -enddef; + if str$="x" : X_ else : Y_ fi +enddef ; -% New: +% New : save graph_background ; color graph_background ; % if defined, fill the frame. def begingraph(expr w, h) = begingroup - save X_, Y_; + save X_, Y_ ; X_.graph_coordinate_type = - Y_.graph_coordinate_type = linear; % coordinate system for each axis - Z_.graph_dimensions = (w,h); % dimensions of graph not counting axes etc. -% Z_.low, Z_.high user-specified coordinate ranges in units used in graph_current_graph - - save graph_finished_graph; - picture graph_finished_graph; % the finished part of the graph - graph_finished_graph = nullpicture; - save graph_current_graph; - picture graph_current_graph; % what has been drawn in current coords - graph_current_graph = nullpicture; - save graph_current_bb; - picture graph_current_bb; % picture whose bbox is graph_current_graph's w/ linewidths 0 - graph_current_bb = nullpicture; - save graph_last_drawn; - picture graph_last_drawn; % result of last gdraw or gfill - graph_last_drawn = nullpicture; - save graph_plot_picture; - picture graph_plot_picture; % a picture from the `plot' option known when plot allowed - save graph_label; - picture graph_label[]; % labels to place around the whole graph when it is done - save graph_autogrid_needed; - boolean graph_autogrid_needed; % whether autogrid is needed - graph_autogrid_needed = true; - save graph_frame_needed; - boolean graph_frame_needed; % whether frame needs to be drawn - graph_frame_needed = true; - save graph_number_of_arrowheads; % number of arrowheads for next gdraw - graph_number_of_arrowheads = 0; + Y_.graph_coordinate_type = linear ; % coordinate system for each axis + Z_.graph_dimensions = (w,h) ; % dimensions of graph not counting axes etc. + %also, Z_.low, Z_.high user-specified coordinate ranges in units used in graph_current_graph + + save graph_finished_graph ; + picture graph_finished_graph ; % the finished part of the graph + graph_finished_graph = nullpicture ; + save graph_current_graph ; + picture graph_current_graph ; % what has been drawn in current coords + graph_current_graph = nullpicture ; + save graph_current_bb ; + picture graph_current_bb ; % picture whose bbox is graph_current_graph's w/ linewidths 0 + graph_current_bb = nullpicture ; + save graph_last_drawn ; + picture graph_last_drawn ; % result of last gdraw or gfill + graph_last_drawn = nullpicture ; + save graph_plot_picture ; + picture graph_plot_picture ; % a picture from the `plot' option known when plot allowed + save graph_label ; + picture graph_label[] ; % labels to place around the whole graph when it is done + save graph_autogrid_needed ; + boolean graph_autogrid_needed ; % whether autogrid is needed + graph_autogrid_needed = true ; + save graph_frame_needed ; + boolean graph_frame_needed ; % whether frame needs to be drawn + graph_frame_needed = true ; + save graph_number_of_arrowheads ; % number of arrowheads for next gdraw + graph_number_of_arrowheads = 0 ; if known graph_background : % new feature! fill origin--(w,0)--(w,h)--(0,h)--cycle withcolor graph_background ; fi -enddef; +enddef ; -% Additional variables not explained above: +% Additional variables not explained above : % graph_modified_lower, graph_modified_higher pairs giving bounds used in auto<x or y> -% graph_exponent, graph_comma variables and macros used in auto<x or y> -% Gc_ temporary macro used in auto<x or y> ???? -% graph_modified_bias an offset to graph_modified_lower and graph_modified_higher to ease computing exponents +% graph_exponent, graph_comma variables and macros used in auto<x or y> +% graph_modified_bias +% an offset to graph_modified_lower and graph_modified_higher to ease computing exponents % Some additional variables function as constants. Most can be modified by the % user to alter the behavior of these macros. -% Not very modifiable: log, linear, -% graph_frame_pair_a, graph_frame_pair_b, graph_margin_pair -% Modifiable: Gtemplate.suffix, Glmarks[], Gumarks, Gemarks, Gmarks, -% Gminlog, Autoform - +% Not very modifiable : log, linear, +% graph_frame_pair_a, graph_frame_pair_b, graph_margin_pair +% Modifiable : Gtemplate.suffix, Glmarks[], Gumarks, Gemarks, Gmarks, +% Gminlog, Autoform -newinternal log, linear; % coordinate system codes -log:=1; linear:=2; +newinternal log, linear ; % coordinate system codes +log :=1 ; linear :=2; +% note that mp-tool.mpiv defines log as log10... - -%%%%%%%%%%%%%%%%%%%%%% Coordinates: setcoords, setrange %%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%% Coordinates : setcoords, setrange %%%%%%%%%%%%%%%%%%%%%% % Graph-related usr input is `user graph coordinates' as specified by arguments % to setcoords. % `Internal graph coordinates' are used for graph_current_graph, graph_current_bb, Z_.low, Z_.high. -% Their meaning depends on the appropriate component of Z_.graph_coordinate_type: +% Their meaning depends on the appropriate component of Z_.graph_coordinate_type : % log means internal graph coords = mlog(user graph coords) % -log means internal graph coords = -mlog(user graph coords) % linear means internal graph coords = (user graph coords) @@ -178,13 +184,14 @@ log:=1; linear:=2; vardef graph_set_default_bounds = % Set default Z_.low, Z_.high - forsuffixes $=low,high: - (if known X_$: whatever else: X_$ fi, if known Y_$: whatever else: Y_$ fi) - = graph_margin_fraction$[llcorner graph_current_bb,urcorner graph_current_bb] + graph_margin_pair$; + forsuffixes $=low,high : + (if known X_$ : whatever else : X_$ fi, if known Y_$ : whatever else : Y_$ fi) + = graph_margin_fraction$[llcorner graph_current_bb,urcorner graph_current_bb] + + graph_margin_pair$ ; endfor -enddef; -pair graph_margin_pair.low, graph_margin_pair.high; -graph_margin_pair.high = -graph_margin_pair.low = (.00002,.00002); +enddef ; +pair graph_margin_pair.low, graph_margin_pair.high ; +graph_margin_pair.high = -graph_margin_pair.low = (.00002,.00002) ; % Set $, $$, $$$ so that shifting by $ then transforming by $$ and then $$$ @@ -192,31 +199,31 @@ graph_margin_pair.high = -graph_margin_pair.low = (.00002,.00002); % `essential bounding box' is either what Z_.low and Z_.high imply or the % result of ignoring pen widths in graph_current_graph. vardef graph_remap(suffix $,$$,$$$) = - save p_; - graph_set_default_bounds; - pair p_, $; $=-Z_.low; - p_ = (max(X_.high-X_.low,.9), max(Y_.high-Y_.low,.9)); - transform $$, $$$; - forsuffixes #=$$,$$$: xpart#=ypart#=xypart#=yxpart#=0; endfor - (Z_.high+$) transformed $$ = p_; - p_ transformed $$$ = Z_.graph_dimensions; -enddef; -graph_margin_fraction.low=-.07; % bbox fraction for default range start -graph_margin_fraction.high=1.07; % bbox fraction for default range stop + save p_ ; + graph_set_default_bounds ; + pair p_, $ ; $=-Z_.low; + p_ = (max(X_.high-X_.low,.9), max(Y_.high-Y_.low,.9)) ; + transform $$, $$$ ; + forsuffixes #=$$,$$$ : xpart#=ypart#=xypart#=yxpart#=0 ; endfor + (Z_.high+$) transformed $$ = p_ ; + p_ transformed $$$ = Z_.graph_dimensions ; +enddef ; +graph_margin_fraction.low=-.07 ; % bbox fraction for default range start +graph_margin_fraction.high=1.07 ; % bbox fraction for default range stop def graph_with_pen_and_color(expr q) = withpen penpart q withcolor - if colormodel q=1: + if colormodel q=1 : false - elseif colormodel q=3: + elseif colormodel q=3 : (greypart q) - elseif colormodel q=5: + elseif colormodel q=5 : (redpart q, greenpart q, bluepart q) - elseif colormodel q=7: + elseif colormodel q=7 : (cyanpart q, magentapart q, yellowpart q, blackpart q) fi -enddef; +enddef ; % Add picture component q to picture @# and change part p to tp, where p is % something from q that needs coordinate transformation. The type of p is pair @@ -224,101 +231,115 @@ enddef; % Pair o is the value of p that makes tp (0,0). This implements the trick % whereby using 1 instead of 0 for th the width or height or the setbounds path % for a label picture suppresses shifting in x or y. -vardef old_graph_picture_conversion@#(expr q, o)(text tp) = - save p; - if stroked q: - path p; p=pathpart q; - addto @# doublepath tp graph_with_pen_and_color(q) dashed dashpart q; - elseif filled q: - path p; p=pathpart q; - addto @# contour tp graph_with_pen_and_color(q); - else: - interim truecorners:=0; - pair p; p=llcorner q; - if urcorner q<>p: p:=p+graph_coordinate_multiplication(o-p,urcorner q-p); fi - addto @# also q shifted ((tp)-llcorner q); - fi -enddef; -% TH: new version from code found at sarovar tracker. This makes +%vardef graph_picture_conversion@#(expr q, o)(text tp) = +% save p ; +% if stroked q : +% path p ; p=pathpart q; +% addto @# doublepath tp graph_with_pen_and_color(q) dashed dashpart q ; +% elseif filled q : +% path p ; p=pathpart q; +% addto @# contour tp graph_with_pen_and_color(q) ; +% else : +% interim truecorners :=0 ; +% pair p ; p=llcorner q; +% if urcorner q<>p : p :=p+graph_coordinate_multiplication(o-p,urcorner q-p) ; fi +% addto @# also q shifted ((tp)-llcorner q) ; +% fi +%enddef ; +% TH : new version from code found at sarovar tracker. This makes % grdaw clip the result to the window defined with setrange vardef graph_picture_conversion@#(expr q, o)(text tp) = - save p, tp_geclipt; - picture tp_geclipt; tp_geclipt:=nullpicture; - if stroked q: - path p; p=pathpart q; + save p, tp_geclipt ; + picture tp_geclipt ; tp_geclipt :=nullpicture; + if stroked q : + path p ; p=pathpart q; %%% --- SDV added - addto tp_geclipt doublepath tp graph_with_pen_and_color(q) dashed dashpart q; - clip tp_geclipt to origin--(xpart Z_.graph_dimensions,0)--Z_.graph_dimensions--(0, ypart Z_.graph_dimensions)--cycle; - addto @# also tp_geclipt; + addto tp_geclipt doublepath tp graph_with_pen_and_color(q) dashed dashpart q ; + clip tp_geclipt to origin--(xpart Z_.graph_dimensions,0)--Z_.graph_dimensions--(0, ypart Z_.graph_dimensions)--cycle ; + addto @# also tp_geclipt ; %%% %%% --- SDV deleted - %%addto @# doublepath tp graph_with_pen_and_color(q) dashed dashpart q; + %%addto @# doublepath tp graph_with_pen_and_color(q) dashed dashpart q ; %%% - elseif filled q: - path p; p=pathpart q; - addto @# contour tp graph_with_pen_and_color(q); - else: - interim truecorners:=0; - pair p; p=llcorner q; - if urcorner q<>p: p:=p+graph_coordinate_multiplication(o-p,urcorner q-p); fi - addto @# also q shifted ((tp)-llcorner q); + elseif filled q : + path p ; p=pathpart q; + addto @# contour tp graph_with_pen_and_color(q) ; + else : + interim truecorners :=0 ; + pair p ; p=llcorner q; + if urcorner q<>p : p :=p+graph_coordinate_multiplication(o-p,urcorner q-p) ; fi + addto @# also q shifted ((tp)-llcorner q) ; fi -enddef; +enddef ; -def graph_coordinate_multiplication(expr a,b) = (xpart a*xpart b, ypart a*ypart b) enddef; +def graph_coordinate_multiplication(expr a,b) = (xpart a*xpart b, ypart a*ypart b) enddef ; -vardef graph_clear_bounds@# = numeric @#.low, @#.high; enddef; +vardef graph_clear_bounds@# = numeric @#.low, @#.high ; enddef; % Finalize anything drawn in the present coordinate system and set up a new % system as requested vardef setcoords(expr tx, ty) = - interim warningcheck:=0; - if length graph_current_graph>0: - save s, S, T; - graph_remap(s, S, T); - for q within graph_current_graph: - graph_picture_conversion.graph_finished_graph(q, -s, p shifted s transformed S transformed T); + interim warningcheck :=0 ; + if length graph_current_graph>0 : + save s, S, T ; + graph_remap(s, S, T) ; + for q within graph_current_graph : + graph_picture_conversion.graph_finished_graph(q,-s,p shifted s transformed S transformed T) ; endfor - graph_current_graph := graph_current_bb := nullpicture; + graph_current_graph := graph_current_bb := nullpicture ; fi - graph_clear_bounds.X_; graph_clear_bounds.Y_; - X_.graph_coordinate_type:=tx; Y_.graph_coordinate_type:=ty; -enddef; + graph_clear_bounds.X_ ; graph_clear_bounds.Y_; + X_.graph_coordinate_type := tx ; Y_.graph_coordinate_type := ty; +enddef ; % Set Z_.low and Z_.high to correspond to given range of user graph % coordinates. The text argument should be a sequence of pairs and/or strings % with 4 components in all. vardef setrange(text t) = - interim warningcheck:=0; - save r_; r_=0; - string r_[]s; + interim warningcheck :=0 ; + save r_ ; r_=0; + string r_[]s ; for x_= - for p_=t: if pair p_: xpart p_, ypart fi p_, endfor: - r_[incr r_] if string x_: s fi = x_; - if r_>2: - graph_set_bounds if r_=3: X_ else: Y_ fi(r_[r_-2] if unknown r_[r_-2]: s fi, x_); + for p_=t : if pair p_ : xpart p_, ypart fi p_, endfor : + r_[incr r_] if string x_ : s fi = x_ ; + if r_>2 : + graph_set_bounds if r_=3 : X_ else : Y_ fi (r_[r_-2] if unknown r_[r_-2] : s fi, x_) ; fi - exitif r_=4; + exitif r_=4 ; endfor -enddef; +enddef ; -% @# is X_ or Y_; l and h are numeric or string -% It would not be OK to set (@#low,@#high) to a pair expression because $ might -% try to rescale @#low when evaluating the right-hand side for @#high. +% @# is X_ or Y_ ; l and h are numeric or string vardef graph_set_bounds@#(expr l, h) = - graph_clear_bounds@#; - if @#graph_coordinate_type>0: - @#low = if abs @#graph_coordinate_type=log: graph_mlog fi if string l : scantokens fi l; - @#high = if abs @#graph_coordinate_type=log: graph_mlog fi if string h : scantokens fi h; - else: - -@#high = if abs @#graph_coordinate_type=log: graph_mlog fi if string l : scantokens fi l; - -@#low = if abs @#graph_coordinate_type=log: graph_mlog fi if string h : scantokens fi h; + graph_clear_bounds@# ; + if @#graph_coordinate_type>0 : + @#low = if unknown l : + whatever + else : + if abs @#graph_coordinate_type=log : graph_mlog fi if string l : scantokens fi l + fi ; + @#high = if unknown h : + whatever + else : + if abs @#graph_coordinate_type=log : graph_mlog fi if string h : scantokens fi h + fi ; + else : + -@#high = if unknown l : + whatever + else : + if abs @#graph_coordinate_type=log : graph_mlog fi if string l : scantokens fi l + fi ; + -@#low = if unknown h : + whatever + else : + if abs @#graph_coordinate_type=log : graph_mlog fi if string h : scantokens fi h + fi ; fi -enddef; +enddef ; @@ -330,36 +351,37 @@ enddef; % x and y parts of each coordinate pair. Boolean parameter c tells whether to % force the result to be polygonal. vardef graph_scan_path(expr p, c)(suffix tx, ty) = - if (str tx="") and (str ty=""): p - else: - save r_; path r_; + if (str tx="") and (str ty="") : p + else : + save r_ ; path r_; r_ := graph_pair_adjust(point 0 of p, tx, ty) - if path p: - for t=1 upto length p: - if c: -- - else: ..controls graph_pair_adjust(postcontrol(t-1) of p, tx, ty) + if path p : + for t=1 upto length p : + if c : -- + else : ..controls graph_pair_adjust(postcontrol(t-1) of p, tx, ty) and graph_pair_adjust(precontrol t of p, tx, ty) .. fi graph_pair_adjust(point t of p, tx, ty) endfor - if cycle p: &cycle fi - fi; - if pair p: point 0 of fi r_ + if cycle p : &cycle fi + fi ; + if pair p : point 0 of fi r_ fi -enddef; -vardef graph_pair_adjust(expr p)(suffix tx, ty) = (tx xpart p, ty ypart p) enddef; +enddef ; +vardef graph_pair_adjust(expr p)(suffix tx, ty) = (tx xpart p, ty ypart p) enddef ; % Convert path p from user graph coords to internal graph coords. vardef graph_convert_user_path_to_internal primary p = - interim warningcheck:=0; - graph_scan_path(p, (abs X_.graph_coordinate_type<>linear) or (abs Y_.graph_coordinate_type<>linear), - if abs X_.graph_coordinate_type=log: graph_mlog fi, - if abs Y_.graph_coordinate_type=log: graph_mlog fi) + interim warningcheck :=0 ; + graph_scan_path(p, + (abs X_.graph_coordinate_type<>linear) or (abs Y_.graph_coordinate_type<>linear), + if abs X_.graph_coordinate_type=log : graph_mlog fi, + if abs Y_.graph_coordinate_type=log : graph_mlog fi) transformed (identity - if X_.graph_coordinate_type<0: xscaled -1 fi - if Y_.graph_coordinate_type<0: yscaled -1 fi) -enddef; + if X_.graph_coordinate_type<0 : xscaled -1 fi + if Y_.graph_coordinate_type<0 : yscaled -1 fi) +enddef ; % Convert label location t_ from user graph coords to internal graph coords. @@ -367,23 +389,23 @@ enddef; % or a single item of non-pair type, just return t_. Unknown coordinates % produce unknown components in the result. vardef graph_label_convert_user_to_internal(text t_) = - save n_; n_=0; - interim warningcheck:=0; - if 0 for x_=t_: +1 if pair x_: +1 fi endfor <= 1: + save n_ ; n_=0; + interim warningcheck :=0 ; + if 0 for x_=t_ : +1 if pair x_ : +1 fi endfor <= 1 : t_ - else: - n_0 = n_1 = 0; + else : + n_0 = n_1 = 0 ; point 0 of graph_convert_user_path_to_internal ( for x_= - for y_=t_: if pair y_: xpart y_, ypart fi y_, endfor - 0, 0: - if known x_: if string x_ : scantokens fi x_ - else: hide(n_[n_]:=whatever) 0 + for y_=t_ : if pair y_ : xpart y_, ypart fi y_, endfor + 0, 0 : + if known x_ : if string x_ : scantokens fi x_ + else : hide(n_[n_] :=whatever) 0 fi - exitif incr n_=2; + exitif incr n_=2 ; ,endfor) + (n_0,n_1) fi -enddef; +enddef ; @@ -393,57 +415,58 @@ enddef; % initial "%", and return true if at least one token is found. The tokens % are stored in @#1, @#2, .. with "" in the last @#[] entry. vardef graph_read_line@#(expr f) = - save n_, s_; string s_; - s_ = readfrom f; - string @#[]; - if s_<>EOF: - @#1 := loptok s_; - n_ = if @#1="%": 0 else: 1 fi; - forever: - @#[incr n_] := loptok s_; - exitif @#[n_]=""; + save n_, s_ ; string s_; + s_ = readfrom f ; + string @#[] ; + if s_<>EOF : + @#0 := s_ ; + @#1 := loptok s_ ; + n_ = if @#1="%" : 0 else : 1 fi ; + forever : + @#[incr n_] := loptok s_ ; + exitif @#[n_]="" ; endfor @#1<>"" - else: false + else : false fi -enddef; +enddef ; % Execute c for each line of data read from file f, and stop at the first % line with no data. Commands c can use line number i and tokens $1, $2, ... def gdata(expr f)(suffix $)(text c) = - for i=1 upto infinity: - exitunless graph_read_line$(f); + for i=1 upto infinity : + exitunless graph_read_line$(f) ; c endfor -enddef; +enddef ; % Read a path from file f. The path is terminated by blank line or EOF. vardef graph_readpath(expr f) = - interim warningcheck:=0; - save s; - gdata(f, s, if i>1:--fi - if s2="": ( i, scantokens s1) - else: (scantokens s1, scantokens s2) fi + interim warningcheck :=0 ; + save s ; + gdata(f, s, if i>1 :--fi + if s2="" : ( i, scantokens s1) + else : (scantokens s1, scantokens s2) fi ) -enddef; +enddef ; % Append coordinates t to polygonal path @#. The coordinates can be numerics, % strings, or a single pair. vardef augment@#(text t) = - interim warningcheck := 0; - if not path begingroup @# endgroup: - Gerr(begingroup @# endgroup, "Cannot augment--not a path"); - else: - def graph_comma= hide(def graph_comma=,enddef) enddef; - if known @#: @#:=@#-- else: @#= fi - (for p=t: - graph_comma if string p: scantokens fi p - endfor); + interim warningcheck := 0 ; + if not path begingroup @# endgroup : + Gerr(begingroup @# endgroup, "Cannot augment--not a path") ; + else : + def graph_comma= hide(def graph_comma=,enddef) enddef ; + if known @# : @# :=@#-- else : @#= fi + (for p=t : + graph_comma if string p : scantokens fi p + endfor) ; fi -enddef; +enddef ; @@ -452,109 +475,113 @@ enddef; % Unknown pair components are set to 0 because glabel and gdotlabel understand % unknown coordinates as `0 in absolute units'. vardef graph_unknown_pair_bbox(expr p) = - if known p: addto graph_current_bb doublepath p; - else: - save x,y; - z = llcorner graph_current_bb; - if unknown xpart p: xpart p= else: x:= fi 0; - if unknown ypart p: ypart p= else: y:= fi 0; - addto graph_current_bb doublepath (p+z); + if known p : addto graph_current_bb doublepath p ; + else : + save x,y ; + z = llcorner graph_current_bb ; + if unknown xpart p : xpart p= else : x := fi 0 ; + if unknown ypart p : ypart p= else : y := fi 0 ; + addto graph_current_bb doublepath (p+z) ; fi - graph_current_bb := image(fill llcorner graph_current_bb..urcorner graph_current_bb--cycle); -enddef; + graph_current_bb := image(fill llcorner graph_current_bb..urcorner graph_current_bb--cycle) ; +enddef ; % Initiate a gdraw or gfill command. This must be done before scanning the % argument, because that could invoke the `if known graph_plot_picture' test in a following % plot option . -def graph_addto = graph_last_drawn:=graph_plot_picture:=nullpicture; addto graph_last_drawn enddef; +def graph_addto = + graph_last_drawn := graph_plot_picture := nullpicture ; addto graph_last_drawn +enddef; % Handle the part of a Gdraw command that uses path or data file p. def graph_draw expr p = - if string p: graph_convert_user_path_to_internal graph_readpath(p) - elseif path p or pair p: graph_convert_user_path_to_internal p - else: graph_error(p,"gdraw argument should be a data file or a path") + if string p : graph_convert_user_path_to_internal graph_readpath(p) + elseif path p or pair p : graph_convert_user_path_to_internal p + else : graph_error(p,"gdraw argument should be a data file or a path") origin fi withpen currentpen graph_withlist _op_ -enddef; +enddef ; % Handle the part of a Gdraw command that uses path or data file p. def graph_fill expr p = - if string p: graph_convert_user_path_to_internal graph_readpath(p) --cycle - elseif cycle p: graph_convert_user_path_to_internal p - else: graph_error(p,"gfill argument should be a data file or a cyclic path") + if string p : graph_convert_user_path_to_internal graph_readpath(p) --cycle + elseif cycle p : graph_convert_user_path_to_internal p + else : graph_error(p,"gfill argument should be a data file or a cyclic path") origin..cycle fi graph_withlist _op_ -enddef; +enddef ; -def gdraw = graph_addto doublepath graph_draw enddef; -def gfill = graph_addto contour graph_fill enddef; +def gdraw = graph_addto doublepath graph_draw enddef ; +def gfill = graph_addto contour graph_fill enddef ; % This is used in graph_draw and graph_fill to allow postprocessing graph_last_drawn -def graph_withlist text t_ = t_; graph_post_draw; enddef; +def graph_withlist text t_ = t_ ; graph_post_draw; enddef; % Set graph_plot_picture so the postprocessing step will plot picture p at each path knot. % Also select nullpen to suppress stroking. def plot expr p = - if known graph_plot_picture: + if known graph_plot_picture : withpen nullpen - hide (graph_plot_picture:=image( - if bounded p: for q within p: graph_addto_currentpicture q endfor % Save memory - else: graph_addto_currentpicture p + hide (graph_plot_picture :=image( + if bounded p : for q within p : graph_addto_currentpicture q endfor % Save memory + else : graph_addto_currentpicture p fi graph_setbounds origin..cycle)) fi -enddef; +enddef ; % This hides a semicolon that could prematurely end graph_withlist's text argument -def graph_addto_currentpicture primary p = addto currentpicture also p; enddef; -def graph_setbounds = setbounds currentpicture to enddef; +def graph_addto_currentpicture primary p = addto currentpicture also p ; enddef; +def graph_setbounds = setbounds currentpicture to enddef ; -def gdrawarrow = graph_number_of_arrowheads:=1; gdraw enddef; -def gdrawdblarrow = graph_number_of_arrowheads:=2; gdraw enddef; +def gdrawarrow = graph_number_of_arrowheads :=1 ; gdraw enddef; +def gdrawdblarrow = graph_number_of_arrowheads :=2 ; gdraw enddef; -% Post-process the filled or stroked picture graph_last_drawn as follows: (1) update -% the bounding box information; (2) transfer it to graph_current_graph unless the pen has -% been set to nullpen to disable stroking; (3) plot graph_plot_picture at each knot. +% Post-process the filled or stroked picture graph_last_drawn as follows : (1) update +% the bounding box information ; (2) transfer it to graph_current_graph unless the pen has +% been set to nullpen to disable stroking ; (3) plot graph_plot_picture at each knot. vardef graph_post_draw = - save p; - path p; p=pathpart graph_last_drawn; - graph_unknown_pair_bbox(p); - if filled graph_last_drawn or not graph_is_null(penpart graph_last_drawn): - addto graph_current_graph also graph_last_drawn; + save p ; + path p ; p=pathpart graph_last_drawn; + graph_unknown_pair_bbox(p) ; + if filled graph_last_drawn or not graph_is_null(penpart graph_last_drawn) : + addto graph_current_graph also graph_last_drawn ; fi - if length graph_plot_picture>0: - for i=0 upto length p if cycle p: -1 fi: - addto graph_current_graph also graph_plot_picture shifted point i of p; + if length graph_plot_picture>0 : + for i=0 upto length p if cycle p : -1 fi : + addto graph_current_graph also graph_plot_picture shifted point i of p ; endfor - picture graph_plot_picture; + picture graph_plot_picture ; fi - if graph_number_of_arrowheads>0: - graph_draw_arrowhead(p, graph_with_pen_and_color(graph_last_drawn)); - if graph_number_of_arrowheads>1: graph_draw_arrowhead(reverse p, graph_with_pen_and_color(graph_last_drawn)); fi - graph_number_of_arrowheads:=0; + if graph_number_of_arrowheads>0 : + graph_draw_arrowhead(p, graph_with_pen_and_color(graph_last_drawn)) ; + if graph_number_of_arrowheads>1 : + graph_draw_arrowhead(reverse p, graph_with_pen_and_color(graph_last_drawn)) ; + fi + graph_number_of_arrowheads :=0 ; fi -enddef; -vardef graph_is_null(expr p) = (urcorner p=origin) and (llcorner p=origin) enddef; +enddef ; +vardef graph_is_null(expr p) = (urcorner p=origin) and (llcorner p=origin) enddef ; -vardef graph_draw_arrowhead(expr p)(text w) = % Draw arrowhead for path p, with list w +vardef graph_draw_arrowhead(expr p)(text w) = % Draw arrowhead for path p, with list w addto graph_current_graph also image(filldraw arrowhead( - graph_arrowhead_extent(precontrol infinity of p, point infinity of p)) w; - graph_setbounds point infinity of p..cycle); -enddef; + graph_arrowhead_extent(precontrol infinity of p, point infinity of p)) w ; + graph_setbounds point infinity of p..cycle) ; +enddef ; vardef graph_arrowhead_extent(expr p, q) = - if p<>q: (q - 100pt*unitvector(q-p)) -- fi + if p<>q : (q - 100pt*unitvector(q-p)) -- fi q -enddef; +enddef ; @@ -562,46 +589,46 @@ enddef; % Argument c is a drawing command that needs an additional argument p that gives % a location in internal graph coords. Draw in graph_current_graph enclosed in a setbounds -% path. Unknown components of p cause the setbounds path to have width or -% height 1 instead of 0. Then graph_unknown_pair_bbox sets these components to 0 and graph_picture_conversion +% path. Unknown components of p cause the setbounds path to have width or height 1 instead of 0. +% Then graph_unknown_pair_bbox sets these components to 0 and graph_picture_conversion % suppresses subsequent repositioning. def graph_draw_label(expr p)(suffix $)(text c) = - save sdim_; pair sdim_; - sdim_ := (if unknown xpart p: 1+ fi 0, if unknown ypart p: 1+ fi 0); - graph_unknown_pair_bbox(p); + save sdim_ ; pair sdim_; + sdim_ := (if unknown xpart p : 1+ fi 0, if unknown ypart p : 1+ fi 0) ; + graph_unknown_pair_bbox(p) ; addto graph_current_graph also - image(c(p); graph_setbounds p--p+sdim_--cycle) _op_ -enddef; + image(c(p) ; graph_setbounds p--p+sdim_--cycle) _op_ +enddef ; % Stash the result drawing command c in the graph_label table using with list w and % an index based on angle laboff$. vardef graph_stash_label(suffix $)(text c) text w = - graph_label[1.5+angle laboff$ /90] = image(c(origin) w); -enddef; + graph_label[1.5+angle laboff$ /90] = image(c(origin) w) ; +enddef ; def graph_label_location primary p = - if pair p: graph_draw_label(p) - elseif numeric p: graph_draw_label(point p of pathpart graph_last_drawn) - else: graph_stash_label + if pair p : graph_draw_label(p) + elseif numeric p : graph_draw_label(point p of pathpart graph_last_drawn) + else : graph_stash_label fi -enddef; +enddef ; % Place label p at user graph coords t using with list w. (t is a time, a pair % or 2 numerics or strings). vardef glabel@#(expr p)(text t) text w = - graph_label_location graph_label_convert_user_to_internal(t) (@#,label@#(p)) w; enddef; + graph_label_location graph_label_convert_user_to_internal(t) (@#,label@#(p)) w ; enddef; % Place label p at user graph coords t using with list w and draw a dot there. % (t is a time, a pair, or 2 numerics or strings). vardef gdotlabel@#(expr p)(text t) text w = - graph_label_location graph_label_convert_user_to_internal(t) (@#,dotlabel@#(p)) w; enddef; + graph_label_location graph_label_convert_user_to_internal(t) (@#,dotlabel@#(p)) w ; enddef; -def OUT = enddef; % location text for outside labels +def OUT = enddef ; % location text for outside labels @@ -610,32 +637,32 @@ def OUT = enddef; % location text for outside labels % Grid lines and tick marks are transformed versions of the templates below. % In the template paths, (0,0) is on the edge of the frame and inward is to % the right. -path Gtemplate.itick, Gtemplate.otick, Gtemplate.grid; -Gtemplate.itick = origin--(7bp,0); -Gtemplate.otick = (-7bp,0)--origin; -Gtemplate.grid = origin--(1,0); +path Gtemplate.itick, Gtemplate.otick, Gtemplate.grid ; +Gtemplate.itick = origin--(7bp,0) ; +Gtemplate.otick = (-7bp,0)--origin ; +Gtemplate.grid = origin--(1,0) ; -vardef itick@#(expr f,u) text w = graph_tick_label(@#,@,false,f,u,w); enddef; +vardef itick@#(expr f,u) text w = graph_tick_label(@#,@,false,f,u,w) ; enddef; -vardef otick@#(expr f,u) text w = graph_tick_label(@#,@,false,f,u,w); enddef; +vardef otick@#(expr f,u) text w = graph_tick_label(@#,@,false,f,u,w) ; enddef; -vardef grid@#(expr f,u) text w = graph_tick_label(@#,@,true,f,u,w); enddef; +vardef grid@#(expr f,u) text w = graph_tick_label(@#,@,true,f,u,w) ; enddef; % Produce a tick or grid mark for label suffix $, Gtemplate suffix $$, % coordinate value u, and with list w. Boolean c tells whether Gtemplate$$ -% needs scaling by X_.graph_dimensions or Y_.graph_dimensions, and f gives a format string or a label -% picture. +% needs scaling by X_.graph_dimensions or Y_.graph_dimensions, +% and f gives a format string or a label picture. def graph_tick_label(suffix $,$$)(expr c, f, u)(text w) = graph_draw_label(graph_label_convert_user_to_internal(graph_generate_label_position($,u)),,draw graph_gridline_picture$($$,c,f,u,w) shifted) -enddef; +enddef ; % Generate label positioning arguments appropriate for label suffix $ and % coordinate u. def graph_generate_label_position(suffix $)(expr u) = - if xpart laboff.$=0: u,whatever else: whatever,u fi -enddef; + if xpart laboff.$=0 : u,whatever else : whatever,u fi +enddef ; % Generate a picture of a grid line labeled with coordinate value u, picture @@ -643,218 +670,223 @@ enddef; % suffix $ identifies entries in the Gtemplate table, and boolean c tells % whether to scale Gtemplate$. vardef graph_gridline_picture@#(suffix $)(expr c, f, u)(text w) = - if unknown u: graph_error(u,"Label coordinate should be known"); nullpicture - else: - save p; path p; - interim warningcheck:=0; - graph_autogrid_needed:=false; + if unknown u : graph_error(u,"Label coordinate should be known") ; nullpicture + else : + save p ; path p; + interim warningcheck :=0 ; + graph_autogrid_needed :=false ; p = Gtemplate$ zscaled -laboff@# - if c: Gxyscale fi - shifted (((.5 + laboff@# dotprod (.5,.5)) * laboff@#) Gxyscale); - image(draw p w; - label@#(if string f: format(f,u) else: f fi, point 0 of p)) + if c : Gxyscale fi + shifted (((.5 + laboff@# dotprod (.5,.5)) * laboff@#) Gxyscale) ; + image(draw p w ; + label@#(if string f : format(f,u) else : f fi, point 0 of p)) fi -enddef; -def Gxyscale = xscaled X_.graph_dimensions yscaled Y_.graph_dimensions enddef; +enddef ; +def Gxyscale = xscaled X_.graph_dimensions yscaled Y_.graph_dimensions enddef ; % Draw the frame or the part corresponding to label suffix @# using with list w. vardef frame@# text w = - graph_frame_needed:=false; - picture p_; + graph_frame_needed :=false ; + picture p_ ; p_ = image(draw - if str@#<>"": subpath round(angle laboff@#*graph_frame_pair_a+graph_frame_pair_b) of fi - unitsquare Gxyscale w); - graph_draw_label((whatever,whatever),,draw p_ shifted); -enddef; -pair graph_frame_pair_a; graph_frame_pair_a=(1,1)/90; % unitsquare subpath is linear in label angle -pair graph_frame_pair_b; graph_frame_pair_b=(.75,2.25); + if str@#<>"" : subpath round(angle laboff@#*graph_frame_pair_a+graph_frame_pair_b) of fi + unitsquare Gxyscale w) ; + graph_draw_label((whatever,whatever),,draw p_ shifted) ; +enddef ; +pair graph_frame_pair_a ; graph_frame_pair_a=(1,1)/90; % unitsquare subpath is linear in label angle +pair graph_frame_pair_b ; graph_frame_pair_b=(.75,2.25); %%%%%%%%%%%%%%%%%%%%%%%%%% Automatic grid selection %%%%%%%%%%%%%%%%%%%%%%%%%% -string Glmarks[]; % marking options per decade for logarithmic scales -string Gumarks; % mark spacing options per decade for linear scales -string Gemarks; % exponent spacing options for logarithmic scales -newinternal Gmarks, Gminlog; -Gmarks := 4; % minimum number marks generated by auto.x or auto.y -Gminlog := 3.0; % revert to uniform marks when largest/smallest < this +string Glmarks[] ; % marking options per decade for logarithmic scales +string Gumarks ; % mark spacing options per decade for linear scales +string Gemarks ; % exponent spacing options for logarithmic scales +newinternal Gmarks, Gminlog ; +Gmarks := 4 ; % minimum number marks generated by auto.x or auto.y +Gminlog := mlog 3 ; % revert to uniform marks when largest/smallest < this -def Gfor(text t) = for i=t endfor enddef; % to shorten the mark templates below -Glmarks[1]="1,2,5"; -Glmarks[2]="1,1.5,2,3,4,5,7"; -Glmarks[3]="1Gfor(6upto10:,i/5)Gfor(5upto10:,i/2)Gfor(6upto9:,i)"; -Glmarks[4]="1Gfor(11upto20:,i/10)Gfor(11upto25:,i/5)Gfor(11upto19:,i/2)"; -Glmarks[5]="1Gfor(21upto40:,i/20)Gfor(21upto50:,i/10)Gfor(26upto49:,i/5)"; -Gumarks="10,5,2"; % start with 10 and go down; a final `,1' is appended -Gemarks="20,10,5,2,1"; +def Gfor(text t) = for i=t endfor enddef ; % to shorten the mark templates below +Glmarks[1]="1,2,5" ; +Glmarks[2]="1,1.5,2,3,4,5,7" ; +Glmarks[3]="1Gfor(6upto10 :,i/5)Gfor(5upto10 :,i/2)Gfor(6upto9 :,i)" ; +Glmarks[4]="1Gfor(11upto20 :,i/10)Gfor(11upto25 :,i/5)Gfor(11upto19 :,i/2)" ; +Glmarks[5]="1Gfor(21upto40 :,i/20)Gfor(21upto50 :,i/10)Gfor(26upto49 :,i/5)" ; +Gumarks="10,5,2" ; % start with 10 and go down; a final `,1' is appended +Gemarks="20,10,5,2,1" ; % Determine the X_ or Y_ bounds on the range to be covered by automatic grid % marks. Suffix @# is X_ or Y_. The result is log or linear to specify the % type of grid spacing to use. Bounds are returned in variables local to -% begingraph..endgraph: pairs graph_modified_lower and graph_modified_higher +% begingraph..endgraph : pairs graph_modified_lower and graph_modified_higher % are upper and lower bounds in % `modified exponential form'. In modified exponential form, (x,y) means % (x/1000)*10^y, where 1000<=abs x<10000. vardef graph_bounds@# = - interim warningcheck:=0; - save l, h; - graph_set_default_bounds; - if @#graph_coordinate_type>0: (l,h) else: -(h,l) fi = (@#low, @#high); - if abs @#graph_coordinate_type=log: - graph_modified_lower := graph_Meform(l)+graph_modified_bias; - graph_modified_higher := graph_Meform(h)+graph_modified_bias; - if h-l >=mlog Gminlog: log else: linear fi - else: - graph_modified_lower := graph_Feform(l)+graph_modified_bias; - graph_modified_higher := graph_Feform(h)+graph_modified_bias; + interim warningcheck :=0 ; + save l, h ; + graph_set_default_bounds ; + if @#graph_coordinate_type>0 : (l,h) else : -(h,l) fi = (@#low, @#high) ; + if abs @#graph_coordinate_type=log : + graph_modified_lower := graph_Meform(l)+graph_modified_bias ; + graph_modified_higher := graph_Meform(h)+graph_modified_bias ; + if h-l >= Gminlog : log else : linear fi + else : + graph_modified_lower := graph_Feform(l)+graph_modified_bias ; + graph_modified_higher := graph_Feform(h)+graph_modified_bias ; linear fi -enddef; -pair graph_modified_bias; graph_modified_bias=(0,3); -pair graph_modified_lower, graph_modified_higher; +enddef ; +pair graph_modified_bias ; graph_modified_bias=(0,3); +pair graph_modified_lower, graph_modified_higher ; % Scan Glmarks[k] and evaluate tokens t for each m where l<=m<=h. def graph_scan_marks(expr k, l, h)(text t) = - for m=scantokens Glmarks[k]: - exitif m>h; - if m>=l: t fi + for m=scantokens Glmarks[k] : + exitif m>h ; + if m>=l : t fi endfor -enddef; +enddef ; % Scan Gmark[k] and evaluate tokens t for each m and e where m*10^e belongs % between l and h (inclusive), where both l and h are in modified exponent form. def graph_scan_mark(expr k, l, h)(text t) = - for e=ypart l upto ypart h: - graph_scan_marks(k, if e>ypart l: 1 else: xpart l/1000 fi, - if e<ypart h: 10 else: xpart h/1000 fi, t) + for e=ypart l upto ypart h : + graph_scan_marks(k, if e>ypart l : 1 else : xpart l/1000 fi, + if e<ypart h : 10 else : xpart h/1000 fi, t) endfor -enddef; +enddef ; % Select a k for which graph_scan_mark(k,...) gives enough marks. vardef graph_select_mark = - save k; - k = 0; - forever: - exitif unknown Glmarks[k+1]; - exitif 0 graph_scan_mark(incr k, graph_modified_lower, graph_modified_higher, +1) >= Gmarks; + save k ; + k = 0 ; + forever : + exitif unknown Glmarks[k+1] ; + exitif 0 graph_scan_mark(incr k, graph_modified_lower, graph_modified_higher, +1) >= Gmarks ; endfor k -enddef; +enddef ; % Try to select an exponent spacing from Gemarks. If successful, set @# and % return true vardef graph_select_exponent_mark@# = - numeric @#; - for e=scantokens Gemarks: - @# = e; - exitif floor(ypart graph_modified_higher/e)-floor(graph_modified_exponent_ypart(graph_modified_lower)/e) >= Gmarks; - numeric @#; + numeric @# ; + for e=scantokens Gemarks : + @# = e ; + exitif floor(ypart graph_modified_higher/e) - + floor(graph_modified_exponent_ypart(graph_modified_lower)/e) >= Gmarks ; + numeric @# ; endfor known @# -enddef; +enddef ; -vardef graph_modified_exponent_ypart(expr p) = ypart p if xpart p=1000: -1 fi enddef; +vardef graph_modified_exponent_ypart(expr p) = ypart p if xpart p=1000 : -1 fi enddef ; % Compute the mark spacing d between xpart graph_modified_lower and xpart graph_modified_higher. vardef graph_tick_mark_spacing = - interim warningcheck:=0; - save m, n, d; - m = Gmarks; + interim warningcheck :=0 ; + save m, n, d ; + m = Gmarks ; n = 1 for i=1 upto - (mlog(xpart graph_modified_higher-xpart graph_modified_lower) - mlog m)/mlogten: - *10 endfor; - if n<=1000: - for x=scantokens Gumarks: - d = n*x; - exitif 0 graph_generate_numbers(d,+1)>=m; - numeric d; + (mlog(xpart graph_modified_higher-xpart graph_modified_lower) - mlog m)/mlogten : + *10 endfor ; + if n<=1000 : + for x=scantokens Gumarks : + d = n*x ; + exitif 0 graph_generate_numbers(d,+1)>=m ; + numeric d ; endfor fi - if known d: d else: n fi -enddef; + if known d : d else : n fi +enddef ; def graph_generate_numbers(expr d)(text t) = - for m = d*ceiling(xpart graph_modified_lower/d) step d until xpart graph_modified_higher: + for m = d*ceiling(xpart graph_modified_lower/d) step d until xpart graph_modified_higher : t endfor -enddef; +enddef ; % Evaluate tokens t for exponents e in multiples of d in the range determined % by graph_modified_lower and graph_modified_higher. def graph_generate_exponents(expr d)(text t) = for e = d*floor(graph_modified_exponent_ypart(graph_modified_lower)/d+1) - step d until d*floor(ypart graph_modified_higher/d): t + step d until d*floor(ypart graph_modified_higher/d) : t endfor -enddef; +enddef ; -% Adjust graph_modified_lower and graph_modified_higher so their exponent parts match and they are in true -% exponent form ((x,y) means x*10^y). Return the new exponent. +% Adjust graph_modified_lower and graph_modified_higher so their exponent parts match +% and they are in true exponent form ((x,y) means x*10^y). Return the new exponent. vardef graph_match_exponents = - interim warningcheck := 0; - save e; - e+3 = if graph_modified_lower=graph_modified_bias: ypart graph_modified_higher - elseif graph_modified_higher=graph_modified_bias: ypart graph_modified_lower - else: max(ypart graph_modified_lower, ypart graph_modified_higher) fi; - forsuffixes $=graph_modified_lower, graph_modified_higher: - $ := (xpart $ for i=ypart $ upto e+2: /(10) endfor, e); + interim warningcheck := 0 ; + save e ; + e+3 = if graph_modified_lower=graph_modified_bias : ypart graph_modified_higher + elseif graph_modified_higher=graph_modified_bias : ypart graph_modified_lower + else : max(ypart graph_modified_lower, ypart graph_modified_higher) fi ; + forsuffixes $=graph_modified_lower, graph_modified_higher : + $ := (xpart $ for i=ypart $ upto e+2 : /(10) endfor, e) ; endfor e -enddef; +enddef ; % Assume e is an integer and either m=0 or 1<=abs(m)<10000. Find m*(10^e) % and represent the result as a string if its absolute value would be at least % 4096 or less than .1. It is OK to return 0 as a string or a numeric. vardef graph_factor_and_exponent_to_string(expr m, e) = - if (e>3)or(e<-4): + if (e>3)or(e<-4) : decimal m & "e" & decimal e - elseif e>=0: - if abs m<infinity/Ten_to[e]: + elseif e>=0 : + if abs m<infinity/Ten_to[e] : m*Ten_to[e] - else: decimal m & "e" & decimal e + else : decimal m & "e" & decimal e fi - else: - save x; x=m/Ten_to[-e]; - if abs x>=.1: x else: decimal m & "e" & decimal e fi + else : + save x ; x=m/Ten_to[-e]; + if abs x>=.1 : x else : decimal m & "e" & decimal e fi fi -enddef; +enddef ; def auto suffix $ = hide(def graph_comma= hide(def graph_comma=,enddef) enddef) - if graph_bounds.graph_suffix($)=log: - if graph_select_exponent_mark.graph_exponent: graph_generate_exponents(graph_exponent, graph_comma graph_factor_and_exponent_to_string(1,e)) - else: - graph_scan_mark(graph_select_mark, graph_modified_lower, graph_modified_higher, graph_comma graph_factor_and_exponent_to_string(m,e)) + if graph_bounds.graph_suffix($)=log : + if graph_select_exponent_mark.graph_exponent : + graph_generate_exponents(graph_exponent, + graph_comma graph_factor_and_exponent_to_string(1,e)) + else : + graph_scan_mark(graph_select_mark, graph_modified_lower, graph_modified_higher, + graph_comma graph_factor_and_exponent_to_string(m,e)) fi - else: - hide(graph_exponent:=graph_match_exponents) - graph_generate_numbers(graph_tick_mark_spacing, graph_comma graph_factor_and_exponent_to_string(m,graph_exponent)) + else : + hide(graph_exponent :=graph_match_exponents) + graph_generate_numbers(graph_tick_mark_spacing, + graph_comma graph_factor_and_exponent_to_string(m,graph_exponent)) fi -enddef; +enddef ; -string Autoform; Autoform = "%g"; +string Autoform ; Autoform = "%g"; %vardef autogrid(suffix tx, ty) text w = -% graph_autogrid_needed:=false; -% if str tx<>"": for x=auto.x: tx(Autoform,x) w; endfor fi -% if str ty<>"": for y=auto.y: ty(Autoform,y) w; endfor fi -%enddef; +% graph_autogrid_needed :=false ; +% if str tx<>"" : for x=auto.x : tx(Autoform,x) w ; endfor fi +% if str ty<>"" : for y=auto.y : ty(Autoform,y) w ; endfor fi +%enddef ; -% We redefine autogrid from graph.mp adding the possibility of differing X and Y +% We redefine autogrid, adding the possibility of differing X and Y % formats. % string Autoform_X ; Autoform_X := "@.0e" ; @@ -900,21 +932,21 @@ enddef ; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% endgraph %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% def endgraph = - if graph_autogrid_needed: autogrid(otick.bot, otick.lft); fi - if graph_frame_needed: frame; fi - setcoords(linear,linear); - interim truecorners:=1; - for b=bbox graph_finished_graph: - setbounds graph_finished_graph to b; - for i=0 step .5 until 3.5: - if known graph_label[i]: - addto graph_finished_graph also graph_label[i] shifted point i of b; + if graph_autogrid_needed : autogrid(otick.bot, otick.lft) ; fi + if graph_frame_needed : frame ; fi + setcoords(linear,linear) ; + interim truecorners :=1 ; + for b=bbox graph_finished_graph : + setbounds graph_finished_graph to b ; + for i=0 step .5 until 3.5 : + if known graph_label[i] : + addto graph_finished_graph also graph_label[i] shifted point i of b ; fi endfor endfor graph_finished_graph endgroup -enddef; +enddef ; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -935,18 +967,18 @@ vardef escaped_format(expr s) = enddef ; vardef strfmt(expr f, x) = - "\MPgraphformat{" & escaped_format(f) & "}{" & (if string x : x else: decimal x fi) & "}" + "\MPgraphformat{" & escaped_format(f) & "}{" & (if string x : x else : decimal x fi) & "}" enddef ; vardef format(expr f, x) = textext(strfmt(f, x)) enddef ; -% A couple of extensions: +% A couple of extensions : -% Define a function plotsymbol() returning a picture: 10 different shapes, +% Define a function plotsymbol() returning a picture : 10 different shapes, % unfilled outline, interior filled with different shades of the background. % This allows overlapping points on a plot to be more distinguishable. -vardef graph_shapesize = .35BodyFontSize enddef ; +vardef graph_shapesize = .33BodyFontSize enddef ; path graph_shape[] ; % (internal) symbol path @@ -1005,9 +1037,9 @@ endfor cycle ; graph_shape[34] := graph_shape[24] rotated 45 ; -% usage: gdraw p plot plotsymbol(1,red,1) ; % a filled red circle -% usage: gdraw p plot plotsymbol(14,blue,0) ; % a blue square -% usage: gdraw p plot plotsymbol(4,green,0.5) ; % a 50% filled green diamond +% usage : gdraw p plot plotsymbol(1,red,1) ; % a filled red circle +% usage : gdraw p plot plotsymbol(14,blue,0) ; % a blue square +% usage : gdraw p plot plotsymbol(4,green,0.5) ; % a 50% filled green diamond def stars(expr c, f) = plotsymbol(25,c,f) enddef ; % a 5-point star def points(expr c, f) = plotsymbol( 0,c,f) enddef ; @@ -1045,6 +1077,19 @@ def plotsymbol(expr n,c,f) = % (number,color,color|number) fi enddef ; +% standard resistance color code: rainbow sequence (from /usr/share/X11/rgb.txt) +color resistance_color[] ; string resistance_name[] ; +resistance_color0 = (0,0,0) ; resistance_name0 = "black" ; +resistance_color1 = (165/255,42/255,42/255) ; resistance_name1 = "brown" ; +resistance_color2 = (1,0,0) ; resistance_name2 = "red" ; +resistance_color3 = (1,165/255,0) ; resistance_name3 = "orange" ; +resistance_color4 = (1,1,0) ; resistance_name4 = "yellow" ; +resistance_color5 = (0,1,0) ; resistance_name5 = "green" ; +resistance_color6 = (0,0,1) ; resistance_name6 = "blue" ; +resistance_color7 = (148/255,0,211/255) ; resistance_name7 = "darkviolet" ; +resistance_color8 = (190/255,190/255,190/255) ; resistance_name8 = "gray" ; +resistance_color9 = (1,1,1) ; resistance_name9 = "white" ; + % The following extensions are not specific to graph and could be moved to metafun... % sort a path. Efficient en memory use, not so efficient in sorting long paths... @@ -1094,7 +1139,7 @@ enddef ; % shift a path, point by point % -% example: +% example : % % p1 := addnoisetopath(p0,(.1normaldeviate,.1normaldeviate)) ; @@ -1103,7 +1148,7 @@ vardef addnoisetopath (suffix p) (text t) = hide(pair p_i) (for i=0 upto length p : if i>0 : -- fi - hide(p_i := point i of p; x := xpart p_i; y := ypart p_i)z shifted t + hide(p_i := point i of p ; x := xpart p_i; y := ypart p_i)z shifted t endfor) fi enddef ; @@ -1119,7 +1164,7 @@ enddef ; % least-squares "fit" to a polynomial % -% example: +% example : % % path p[] ; % numeric a[] ; a0 := 1 ; a1 := .1 ; a2 := .01 ; a3 := .001 ; a4 := 0.0001 ; @@ -1136,7 +1181,7 @@ enddef ; % linear_fit(p1, c, 1) ; % gdraw functionpath(p1,linear_function(c,x)) dashed evenly ; -% a polynomial function: +% a polynomial function : % % y = a0 + a1 * x + a2 * x^2 + ... + a[n] * x^n @@ -1144,7 +1189,7 @@ vardef polynomial_function (suffix $) (expr n, x) = (for j=0 upto n : + $[j]*(x**j) endfor) % no ; enddef ; -% find the determinant of a (n+1)*(n+1) matrix; indices run from 0 to n +% find the determinant of a (n+1)*(n+1) matrix ; indices run from 0 to n vardef det (suffix $) (expr n) = hide( @@ -1173,8 +1218,8 @@ vardef det (suffix $) (expr n) = exitif determinant=0 ; determinant := determinant * $[k][k] ; if k<n : % subtract row k from lower rows to get a diagonal matrix - for j=k+1 upto n: - for i=k+1 upto n: + for j=k+1 upto n : + for i=k+1 upto n : $[j][i] := $[j][i]-$[j][k]*$[k][i]/$[k][k] ; endfor endfor @@ -1188,7 +1233,7 @@ numeric fit_chi_squared ; % least-squares fit of a polynomial $ of order n to a path p (unweighted) % -% reference: P. R. Bevington, "Data Reduction and Error Analysis for the Physical +% reference : P. R. Bevington, "Data Reduction and Error Analysis for the Physical % Sciences", McGraw-Hill, New York 1969. vardef polynomial_fit (suffix p, $) (expr n) (text t) = @@ -1208,7 +1253,7 @@ vardef polynomial_fit (suffix p, $) (expr n) (text t) = sumy[i] := 0 ; endfor for i=0 upto length p : - clearxy; z = point i of p ; + clearxy ; z = point i of p ; w := if length(t) > 0 : t else : 1 fi ; % weight x1 := w ; for j=0 upto 2n : @@ -1314,9 +1359,9 @@ vardef power_law_fit (suffix p, $) (text t) = $1 := exp(a0) ; enddef ; -% gaussian: y = a2 * exp(-ln(2)*((x-a0)/a1)^2) +% gaussian : y = a2 * exp(-ln(2)*((x-a0)/a1)^2) % -% a1 is the hwhm; sigma := a1/sqrt(2ln(2)) or a1/1.17741 +% a1 is the hwhm ; sigma := a1/sqrt(2ln(2)) or a1/1.17741 newinternal lntwo ; lntwo := ln(2) ; % brrr, why not inline it |