summaryrefslogtreecommitdiff
path: root/metapost/context/base/mp-grap.mpiv
diff options
context:
space:
mode:
Diffstat (limited to 'metapost/context/base/mp-grap.mpiv')
-rw-r--r--metapost/context/base/mp-grap.mpiv336
1 files changed, 198 insertions, 138 deletions
diff --git a/metapost/context/base/mp-grap.mpiv b/metapost/context/base/mp-grap.mpiv
index 417bfbe69..4fd8ee5bd 100644
--- a/metapost/context/base/mp-grap.mpiv
+++ b/metapost/context/base/mp-grap.mpiv
@@ -17,7 +17,10 @@ boolean context_grap ; context_grap := true ;
% Below is a modified graph.mp
-if epsilon/4 = 0 : % numbersystem="scaled" : (not reliable...)
+show numbersystem, numberprecision ;
+
+%if epsilon/4 = 0 :
+if numbersystem <> "double" :
errmessage "The graph macros require the double precision number system." ;
endinput ;
fi
@@ -52,11 +55,11 @@ fi
% endgraph end of graph--the result is a picture
% option `plot <picture>' draws picture at each path knot, turns off pen
-% Gtemplate.<tickcmd> template paths for tick marks and grid lines
+% graph_template.<tickcmd> template paths for tick marks and grid lines
% graph_margin_fraction.low,
% graph_margin_fraction.high fractions determining margins when no setrange
-% Glmarks[], Gumarks, Gemarks loop text strings used by auto.<x or y>
-% Gmarks, Gminlog numeric parameters used by auto.<x or y>
+% graph_log_marks[], graph_lin_marks, graph_exp_marks loop text strings used by auto.<x or y>
+% graph_minimum_number_of_marks, graph_log_minimum numeric parameters used by auto.<x or y>
% Autoform is the format string used by autogrid
% Autoform_X, Autoform_Y if defined, are used instead
@@ -64,23 +67,27 @@ fi
% are of the form X_.<suffix>, Y_.<suffix>, or Z_.<suffix>, or they start
% with `graph_'
-% Depends on :
-input string.mp
+% Used to depend on :
+
+% input string.mp
% Private version of a few marith macros, fixed for double math...
-newinternal Mzero; Mzero := -16384; % Anything at least this small is treated as zero
-newinternal mlogten ; mlogten := mlog(10) ;
-newinternal singleinfinity ; singleinfinity := 2**128 ;
-newinternal doubleinfinity ; doubleinfinity := 2**1024 ;
-% Note that we get arithmetic overflows if we set to -doubleinfinity below.
-% (but "only on odd days"...)
+
+newinternal Mzero ; Mzero := -16384; % Anything at least this small is treated as zero
+newinternal mlogten ; mlogten := mlog(10) ;
+newinternal largestmantissa ; largestmantissa := 2**52 ; % internal double warningcheck
+newinternal singleinfinity ; singleinfinity := 2**128 ;
+newinternal doubleinfinity ; doubleinfinity := 2**1024 ;
+%Mzero := -largestmantissa ; % Note that we get arithmetic overflows if we set to -doubleinfinity
% Safely convert a number to mlog form, trapping zero.
+
vardef graph_mlog primary x =
if unknown x: whatever
elseif x=0: Mzero
else: mlog(abs x) fi
enddef ;
+
vardef graph_exp primary x =
if unknown x: whatever
elseif x<=Mzero: 0
@@ -89,21 +96,25 @@ enddef ;
% and add the following for utility/completeness
% (replacing the definitions in mp-tool.mpiv).
+
vardef logten primary x =
if unknown x: whatever
elseif x=0: Mzero
else: mlog(abs x)/mlog(10) fi
enddef ;
+
vardef ln primary x =
if unknown x: whatever
elseif x=0: Mzero
else: mlog(abs x)/256 fi
enddef ;
+
vardef exp primary x =
if unknown x: whatever
elseif x<= Mzero: 0
else: (mexp 256)**x fi
enddef ;
+
vardef powten primary x =
if unknown x: whatever
elseif x<= Mzero: 0
@@ -112,6 +123,7 @@ 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 :
@@ -122,6 +134,7 @@ vardef graph_Meform(expr x) =
enddef ;
% Modified from above.
+
vardef graph_Feform(expr x) =
interim warningcheck :=0 ;
if x=0 : origin
@@ -146,6 +159,7 @@ def graph_suffix(suffix $) = % convert from x or y to X_ or Y_
enddef ;
% New :
+
save graph_background ; color graph_background ; % if defined, fill the frame.
save graph_close_file ; boolean graph_close_file ; graph_close_file = false ;
@@ -200,17 +214,20 @@ enddef ;
% 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
+% Modifiable : graph_template.suffix,
+% graph_log_marks[], graph_lin_marks, graph_exp_marks,
+% graph_minimum_number_of_marks,
+% graph_log_minimum, Autoform
newinternal log, linear ; % coordinate system codes
log :=1 ; linear :=2;
+
% note that mp-tool.mpiv defines log as log10.
%%%%%%%%%%%%%%%%%%%%%% Coordinates : setcoords, setrange %%%%%%%%%%%%%%%%%%%%%%
-% Graph-related usr input is `user graph coordinates' as specified by arguments
+% Graph-related user 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 :
@@ -227,14 +244,15 @@ vardef graph_set_default_bounds = % Set default Z_.low, Z_.high
graph_margin_pair$ ;
endfor
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 $$$ maps
+% the essential bounding box of graph_current_graph into (0,0)..Z_.graph_dimensions.
+% The `essential bounding box' is either what Z_.low and Z_.high imply
+% or the result of ignoring pen widths in graph_current_graph.
-% Set $, $$, $$$ so that shifting by $ then transforming by $$ and then $$$
-% maps the essential bounding box of graph_current_graph into (0,0)..Z_.graph_dimensions. The
-% `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 ;
@@ -245,10 +263,10 @@ vardef graph_remap(suffix $,$$,$$$) =
(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 :
@@ -268,7 +286,7 @@ enddef ;
% Pair o is the value of p that makes tp (0,0). This implements the trick
% whereby using 1 instead of 0 for the width or height or the setbounds path
% for a label picture suppresses shifting in x or y.
-%
+
%vardef graph_picture_conversion@#(expr q, o)(text tp) =
% save p ;
% if stroked q :
@@ -284,8 +302,9 @@ enddef ;
% addto @# also q shifted ((tp)-llcorner q) ;
% fi
%enddef ;
-%
+
% This new version makes gdraw clip the result to the window defined with setrange
+
vardef graph_picture_conversion@#(expr q, o)(text tp) =
save p ;
save do_clip, tp_clipped ; boolean do_clip ; do_clip := true ;
@@ -315,12 +334,11 @@ 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;
-
% 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 :
@@ -335,10 +353,10 @@ vardef setcoords(expr tx, ty) =
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;
@@ -353,8 +371,8 @@ vardef setrange(text t) =
endfor
enddef ;
-
% @# 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 :
@@ -382,15 +400,12 @@ vardef graph_set_bounds@#(expr l, h) =
fi
enddef ;
-
-
-
-
%%%%%%%%%%%%%%%%%%%%%%%%% Converting path coordinates %%%%%%%%%%%%%%%%%%%%%%%%%
% Find the result of scanning path p and using macros tx and ty to adjust the
% 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 :
@@ -409,26 +424,29 @@ vardef graph_scan_path(expr p, c)(suffix tx, ty) =
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 ;
+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)
- transformed (identity
- if X_.graph_coordinate_type<0 : xscaled -1 fi
- if Y_.graph_coordinate_type<0 : yscaled -1 fi)
+ if known p :
+ 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)
+ fi
enddef ;
-
% Convert label location t_ from user graph coords to internal graph coords.
% The label location should be a pair, or two numbers/strings. If t_ is empty
% 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 ;
@@ -448,23 +466,56 @@ vardef graph_label_convert_user_to_internal(text t_) =
fi
enddef ;
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Reading data files %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Read a line from file f, extract whitespace-separated tokens ignoring any
% initial "%", and return true if at least one token is found. The tokens
% are stored in @#1, @#2, .. with "" in the last @#[] entry.
+
+% String manipulation routines for MetaPost
+% It is harmless to input this file more than once.
+
+vardef isdigit primary d =
+ ("0"<=d)and(d<="9")
+enddef ;
+
+% Number of initial characters of string s where `c <character>' is true
+
+vardef graph_cspan(expr s)(text c) =
+ 0
+ for i=1 upto length s:
+ exitunless c substring (i-1,i) of s;
+ + 1
+ endfor
+enddef ;
+
+% String s is composed of items separated by white space. Lop off the first
+% item and the surrounding white space and return just the item.
+
+vardef graph_loptok suffix s =
+ save t, k;
+ k = graph_cspan(s," ">=);
+ if k > 0 :
+ s := substring(k,infinity) of s ;
+ fi
+ k := graph_cspan(s," "<);
+ string t;
+ t = substring (0,k) of s;
+ s := substring (k,infinity) of s;
+ s := substring (graph_cspan(s," ">=),infinity) of s;
+ t
+enddef ;
+
vardef graph_read_line@#(expr f) =
save n_, s_ ; string s_;
s_ = readfrom f ;
string @#[] ;
if s_<>EOF :
@#0 := s_ ;
- @#1 := loptok s_ ;
+ @#1 := graph_loptok s_ ;
n_ = if @#1="%" : 0 else : 1 fi ;
forever :
- @#[incr n_] := loptok s_ ;
+ @#[incr n_] := graph_loptok s_ ;
exitif @#[n_]="" ;
endfor
@#1<>""
@@ -472,12 +523,13 @@ vardef graph_read_line@#(expr f) =
fi
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, ...
+% and j is the number of fields.
+
def gdata(expr f)(suffix $)(text c) =
- boolean flag ;
- for i=1 upto infinity :
+ %boolean flag ; % not used?
+ for i=1 upto largestmantissa :
exitunless graph_read_line$(f) ;
c
endfor
@@ -486,8 +538,8 @@ def gdata(expr f)(suffix $)(text c) =
fi
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 ;
@@ -497,9 +549,9 @@ vardef graph_readpath(expr f) =
)
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 :
@@ -513,12 +565,11 @@ vardef augment@#(text t) =
fi
enddef ;
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Drawing and filling %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 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) =
interim warningcheck:=0 ;
if known p : addto graph_current_bb doublepath p ;
@@ -535,6 +586,7 @@ 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 =
def graph_errorbar_text = enddef ;
color graph_foreground ;
@@ -542,8 +594,8 @@ 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.
-% Handle the part of a Gdraw command that uses path or data file p.
def graph_draw expr p =
if string p : hide(graph_last_path := graph_readpath(p) ;)
graph_convert_user_path_to_internal graph_last_path
@@ -556,8 +608,8 @@ def graph_draw expr p =
withpen currentpen graph_withlist _op_
enddef ;
+% Handle the part of a gdraw command that uses path or data file p.
-% Handle the part of a Gdraw command that uses path or data file p.
def graph_fill expr p =
if string p : hide(graph_last_path := graph_readpath(p) --cycle ;)
graph_convert_user_path_to_internal graph_last_path
@@ -571,8 +623,8 @@ 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 witherrorbars(text t) text options =
@@ -584,6 +636,8 @@ def witherrorbars(text t) text options =
options
enddef ;
+% new feature: graph_errorbars
+
picture graph_errorbar_picture ; graph_errorbar_picture := image(draw (left--right) scaled .5 ;) ;
%picture graph_xbar_picture ; graph_xbar_picture := image(draw (down--up) scaled .5 ;) ;
%picture graph_ybar_picture ; graph_ybar_picture := image(draw (left--right) scaled .5 ;) ;
@@ -646,6 +700,7 @@ 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 :
withpen nullpen
@@ -657,20 +712,19 @@ def plot expr p =
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 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.
+
vardef graph_post_draw =
- save p ;
- path p ; p=pathpart 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 ;
@@ -687,17 +741,23 @@ vardef graph_post_draw =
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 ;
+ graph_number_of_arrowheads := 0 ;
fi
enddef ;
-vardef graph_is_null(expr p) = (urcorner p=origin) and (llcorner p=origin) 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
+ %save r ; r := angle(precontrol infinity of p shifted -point infinity of p) ;
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) ;
+ image(fill arrowhead (graph_arrowhead_extent(precontrol infinity of p,point infinity of p)) w ;
+ draw arrowhead (graph_arrowhead_extent(precontrol infinity of p,point infinity of p)) w
+ undashed ;
+%if (r mod 90 <> 0) : % orientation can be wrong due to remapping
+% draw textext("\tfxx " & decimal r) shifted point infinity of p withcolor blue ;
+%fi
+ graph_setbounds point infinity of p..cycle ;
+ ) ; % rotatedabout(point infinity of p,-r) ;
enddef ;
vardef graph_arrowhead_extent(expr p, q) =
@@ -705,8 +765,6 @@ vardef graph_arrowhead_extent(expr p, q) =
q
enddef ;
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Drawing labels %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Argument c is a drawing command that needs an additional argument p that gives
@@ -714,6 +772,7 @@ enddef ;
% 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) ;
@@ -722,14 +781,13 @@ def graph_draw_label(expr p)(suffix $)(text c) =
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 mfun_laboff$.
+
vardef graph_stash_label(suffix $)(text c) text w =
graph_label[1.5+angle mfun_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)
@@ -737,33 +795,31 @@ def graph_label_location primary p =
fi
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;
-
% 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;
-
def OUT = enddef ; % location text for outside labels
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%% Grid lines, ticks, etc. %%%%%%%%%%%%%%%%%%%%%%%%%%
% 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.tick, Gtemplate.itick, Gtemplate.otick, Gtemplate.grid ;
-Gtemplate.tick = (-3.5bp,0)--(3.5bp,0) ;
-Gtemplate.itick = origin--(7bp,0) ;
-Gtemplate.otick = (-7bp,0)--origin ;
-Gtemplate.grid = origin--(1,0) ;
+
+path graph_template.tick, graph_template.itick, graph_template.otick, graph_template.grid ;
+graph_template.tick = (-3.5bp,0)--(3.5bp,0) ;
+graph_template.itick = origin--(7bp,0) ;
+graph_template.otick = (-7bp,0)--origin ;
+graph_template.grid = origin--(1,0) ;
vardef tick@#(expr f,u) text w = graph_tick_label(@#,@,false,f,u,w) ; enddef;
@@ -774,75 +830,82 @@ 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;
-% Produce a tick or grid mark for label suffix $, Gtemplate suffix $$,
-% coordinate value u, and with list w. Boolean c tells whether Gtemplate$$
+% Produce a tick or grid mark for label suffix $, graph_template suffix $$,
+% coordinate value u, and with list w. Boolean c tells whether graph_template$$
% 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)
+ graph_draw_label(graph_label_convert_user_to_internal(graph_generate_label_position($,u)),,
+ draw graph_gridline_picture$($$,c,f,u,w) shifted)
enddef ;
-
% Generate label positioning arguments appropriate for label suffix $ and
% coordinate u.
+
def graph_generate_label_position(suffix $)(expr u) =
- if xpart mfun_laboff.$=0 : u,whatever else : whatever,u fi
+ if pair u : u elseif xpart mfun_laboff.$=0 : u,whatever else : whatever,u fi
enddef ;
-
% Generate a picture of a grid line labeled with coordinate value u, picture
% or format string f, and with list w. Suffix @# is bot, top, lft, or rt,
-% suffix $ identifies entries in the Gtemplate table, and boolean c tells
-% whether to scale Gtemplate$.
+% suffix $ identifies entries in the graph_template table, and boolean c tells
+% whether to scale graph_template$.
+
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 ;
- p = Gtemplate$ zscaled -mfun_laboff@#
- if c : Gxyscale fi
- shifted (((.5 + mfun_laboff@# dotprod (.5,.5)) * mfun_laboff@#) Gxyscale) ;
+ p = graph_template$ zscaled -mfun_laboff@#
+ if c : graph_xyscale fi
+ shifted (((.5 + mfun_laboff@# dotprod (.5,.5)) * mfun_laboff@#) graph_xyscale) ;
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 ;
+def graph_xyscale = 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_ ;
p_ = image(draw
if str@#<>"" : subpath round(angle mfun_laboff@#*graph_frame_pair_a+graph_frame_pair_b) of fi
- unitsquare Gxyscale w) ;
+ unitsquare graph_xyscale 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);
-
-
+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 := mlog 3 ; % revert to uniform marks when largest/smallest < this
+string graph_log_marks[] ; % marking options per decade for logarithmic scales
+string graph_lin_marks ; % mark spacing options per decade for linear scales
+string graph_exp_marks ; % exponent spacing options for logarithmic scales
+newinternal graph_minimum_number_of_marks, graph_log_minimum ;
+graph_minimum_number_of_marks := 4 ; % minimum number marks generated by auto.x or auto.y
+graph_log_minimum := 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
-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" ;
+graph_log_marks[1]="1,2,5" ;
+graph_log_marks[2]="1,1.5,2,3,4,5,7" ;
+graph_log_marks[3]="1Gfor(6upto10 :,i/5)Gfor(5upto10 :,i/2)Gfor(6upto9 :,i)" ;
+graph_log_marks[4]="1Gfor(11upto20 :,i/10)Gfor(11upto25 :,i/5)Gfor(11upto19 :,i/2)" ;
+graph_log_marks[5]="1Gfor(21upto40 :,i/20)Gfor(21upto50 :,i/10)Gfor(26upto49 :,i/5)" ;
+graph_lin_marks="10,5,2" ; % start with 10 and go down; a final `,1' is appended
+graph_exp_marks="20,10,5,2,1" ;
+Ten_to0 = 1 ;
+Ten_to1 = 10 ;
+Ten_to2 = 100 ;
+Ten_to3 = 1000 ;
+Ten_to4 = 10000 ;
% 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
@@ -851,6 +914,7 @@ Gemarks="20,10,5,2,1" ;
% 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 ;
@@ -859,28 +923,29 @@ vardef graph_bounds@# =
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
+ if h-l >= graph_log_minimum : 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 ;
+% Scan graph_log_marks[k] and evaluate tokens t for each m where l<=m<=h.
-% 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] :
+ for m=scantokens graph_log_marks[k] :
exitif m>h ;
if m>=l : t fi
endfor
enddef ;
-
-% Scan Gmark[k] and evaluate tokens t for each m and e where m*10^e belongs
+% Scan graph_log_marks[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,
@@ -888,27 +953,29 @@ def graph_scan_mark(expr k, l, h)(text t) =
endfor
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 ;
+ exitif unknown graph_log_marks[k+1] ;
+ exitif 0 graph_scan_mark(incr k, graph_modified_lower, graph_modified_higher, +1)
+ >= graph_minimum_number_of_marks ;
endfor
k
enddef ;
-
-% Try to select an exponent spacing from Gemarks. If successful, set @# and
+% Try to select an exponent spacing from graph_exp_marks. If successful, set @# and
% return true
+
vardef graph_select_exponent_mark@# =
numeric @# ;
- for e=scantokens Gemarks :
+ for e=scantokens graph_exp_marks :
@# = e ;
exitif floor(ypart graph_modified_higher/e) -
- floor(graph_modified_exponent_ypart(graph_modified_lower)/e) >= Gmarks ;
+ floor(graph_modified_exponent_ypart(graph_modified_lower)/e)
+ >= graph_minimum_number_of_marks ;
numeric @# ;
endfor
known @#
@@ -916,17 +983,17 @@ 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 ;
+ m = graph_minimum_number_of_marks ;
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 :
+ for x=scantokens graph_lin_marks :
d = n*x ;
exitif 0 graph_generate_numbers(d,+1)>=m ;
numeric d ;
@@ -935,25 +1002,24 @@ vardef graph_tick_mark_spacing =
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 :
t
endfor
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
endfor
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.
+
vardef graph_match_exponents =
interim warningcheck := 0 ;
save e ;
@@ -966,10 +1032,10 @@ vardef graph_match_exponents =
e
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) :
decimal m & "e" & decimal e
@@ -984,7 +1050,6 @@ vardef graph_factor_and_exponent_to_string(expr m, e) =
fi
enddef ;
-
def auto suffix $ =
hide(def graph_comma= hide(def graph_comma=,enddef) enddef)
if graph_bounds.graph_suffix($)=log :
@@ -1002,7 +1067,6 @@ def auto suffix $ =
fi
enddef ;
-
string Autoform ; Autoform = "%g";
%vardef autogrid(suffix tx, ty) text w =
@@ -1053,12 +1117,11 @@ vardef autogrid(suffix tx, ty) text w =
fi
enddef ;
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% endgraph %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
def endgraph =
if graph_autogrid_needed : autogrid(otick.bot, otick.lft) ; fi
- if graph_frame_needed : frame ; fi
+ if graph_frame_needed : frame ; fi
setcoords(linear,linear) ;
interim truecorners :=1 ;
for b=bbox graph_finished_graph :
@@ -1075,14 +1138,9 @@ enddef ;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% We format in luatex (using \mathematics{}) ...
% we could pass via variables and save escaping as that is inefficient
-Ten_to0 = 1 ;
-Ten_to1 = 10 ;
-Ten_to2 = 100 ;
-Ten_to3 = 1000 ;
-Ten_to4 = 10000 ;
-
if unknown context_mlib :
vardef escaped_format(expr s) =
@@ -1108,6 +1166,8 @@ if unknown context_mlib :
fi ;
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
% A couple of extensions :
% Define a function plotsymbol() returning a picture : 10 different shapes,