diff options
author | Context Git Mirror Bot <phg42.2a@gmail.com> | 2014-05-03 13:55:34 +0200 |
---|---|---|
committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2014-05-03 13:55:34 +0200 |
commit | 624cbb5da392e9403984dd1cf368c0d408b1c2a8 (patch) | |
tree | 489c049ac849bb5bbce7d32e4df477872c58373d /metapost/context/base/mp-grap.mpiv | |
parent | 088de88944c1f2254250bb448c7371a87ff7ee39 (diff) | |
download | context-624cbb5da392e9403984dd1cf368c0d408b1c2a8.tar.gz |
2014-01-03 00:42:00
Diffstat (limited to 'metapost/context/base/mp-grap.mpiv')
-rw-r--r-- | metapost/context/base/mp-grap.mpiv | 268 |
1 files changed, 124 insertions, 144 deletions
diff --git a/metapost/context/base/mp-grap.mpiv b/metapost/context/base/mp-grap.mpiv index 6d69c0b1e..417bfbe69 100644 --- a/metapost/context/base/mp-grap.mpiv +++ b/metapost/context/base/mp-grap.mpiv @@ -52,11 +52,11 @@ fi % endgraph end of graph--the result is a picture % option `plot <picture>' draws picture at each path knot, turns off pen -% graph_template.<tickcmd> template paths for tick marks and grid lines +% Gtemplate.<tickcmd> template paths for tick marks and grid lines % graph_margin_fraction.low, % graph_margin_fraction.high fractions determining margins when no setrange -% 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> +% Glmarks[], Gumarks, Gemarks loop text strings used by auto.<x or y> +% Gmarks, Gminlog 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 @@ -65,26 +65,22 @@ fi % with `graph_' % Depends 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 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 +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"...) % 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 @@ -93,25 +89,21 @@ 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 @@ -120,7 +112,6 @@ 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 : @@ -131,7 +122,6 @@ vardef graph_Meform(expr x) = enddef ; % Modified from above. - vardef graph_Feform(expr x) = interim warningcheck :=0 ; if x=0 : origin @@ -156,7 +146,6 @@ 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 ; @@ -211,20 +200,17 @@ 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 : graph_template.suffix, -% graph_log_marks[], graph_lin_marks, graph_exp_marks, -% graph_minimum_number_of_marks, -% graph_log_minimum, Autoform +% Modifiable : Gtemplate.suffix, Glmarks[], Gumarks, Gemarks, Gmarks, +% Gminlog, 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 user input is `user graph coordinates' as specified by arguments +% 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 : @@ -241,15 +227,14 @@ 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 ; @@ -260,10 +245,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 : @@ -283,7 +268,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 : @@ -299,9 +284,8 @@ 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 ; @@ -331,11 +315,12 @@ 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 : @@ -350,10 +335,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; @@ -368,8 +353,8 @@ vardef setrange(text t) = endfor enddef ; -% @# is X_ or Y_ ; l and h are numeric or string +% @# 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 : @@ -397,12 +382,15 @@ 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 : @@ -421,11 +409,10 @@ 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 ; -% Convert path p from user graph coords to internal graph coords. +% 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, @@ -437,11 +424,11 @@ vardef graph_convert_user_path_to_internal primary p = if Y_.graph_coordinate_type<0 : yscaled -1 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 ; @@ -461,12 +448,13 @@ 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. - vardef graph_read_line@#(expr f) = save n_, s_ ; string s_; s_ = readfrom f ; @@ -484,9 +472,9 @@ 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, ... - def gdata(expr f)(suffix $)(text c) = boolean flag ; for i=1 upto infinity : @@ -498,8 +486,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. +% 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 ; @@ -509,9 +497,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 : @@ -525,11 +513,12 @@ 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 ; @@ -546,7 +535,6 @@ 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 ; @@ -554,8 +542,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 @@ -568,8 +556,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 @@ -583,8 +571,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 +% 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 = @@ -596,8 +584,6 @@ 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 ;) ; @@ -660,7 +646,6 @@ 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 @@ -672,19 +657,20 @@ 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 ; @@ -701,23 +687,17 @@ 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_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(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) ; + image(filldraw arrowhead( + 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) = @@ -725,6 +705,8 @@ 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 @@ -732,7 +714,6 @@ 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) ; @@ -741,13 +722,14 @@ 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) @@ -755,31 +737,33 @@ 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 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) ; +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) ; vardef tick@#(expr f,u) text w = graph_tick_label(@#,@,false,f,u,w) ; enddef; @@ -790,82 +774,75 @@ 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 $, graph_template suffix $$, -% coordinate value u, and with list w. Boolean c tells whether graph_template$$ +% 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. - 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 pair u : u elseif xpart mfun_laboff.$=0 : u,whatever else : whatever,u fi + if 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 graph_template table, and boolean c tells -% whether to scale graph_template$. - +% 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 ; - p = graph_template$ zscaled -mfun_laboff@# - if c : graph_xyscale fi - shifted (((.5 + mfun_laboff@# dotprod (.5,.5)) * mfun_laboff@#) graph_xyscale) ; + p = Gtemplate$ zscaled -mfun_laboff@# + if c : Gxyscale fi + shifted (((.5 + mfun_laboff@# dotprod (.5,.5)) * mfun_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 ; -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 graph_xyscale w) ; + 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_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 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 -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" ; +%%%%%%%%%%%%%%%%%%%%%%%%%% 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 + +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" ; -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 @@ -874,7 +851,6 @@ Ten_to4 = 10000 ; % 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 ; @@ -883,29 +859,28 @@ 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 >= graph_log_minimum : log else : linear fi + 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 ; -% 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 graph_log_marks[k] : + for m=scantokens Glmarks[k] : exitif m>h ; if m>=l : t fi endfor enddef ; -% 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. +% 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, @@ -913,29 +888,27 @@ def graph_scan_mark(expr k, l, h)(text t) = endfor enddef ; -% Select a k for which graph_scan_mark(k,...) gives enough marks. +% Select a k for which graph_scan_mark(k,...) gives enough marks. vardef graph_select_mark = save k ; k = 0 ; forever : - 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 ; + exitif unknown Glmarks[k+1] ; + exitif 0 graph_scan_mark(incr k, graph_modified_lower, graph_modified_higher, +1) >= Gmarks ; endfor k enddef ; -% Try to select an exponent spacing from graph_exp_marks. If successful, set @# and -% return true +% Try to select an exponent spacing from Gemarks. If successful, set @# and +% return true vardef graph_select_exponent_mark@# = numeric @# ; - for e=scantokens graph_exp_marks : + for e=scantokens Gemarks : @# = e ; exitif floor(ypart graph_modified_higher/e) - - floor(graph_modified_exponent_ypart(graph_modified_lower)/e) - >= graph_minimum_number_of_marks ; + floor(graph_modified_exponent_ypart(graph_modified_lower)/e) >= Gmarks ; numeric @# ; endfor known @# @@ -943,17 +916,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. +% 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 = graph_minimum_number_of_marks ; + 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 graph_lin_marks : + for x=scantokens Gumarks : d = n*x ; exitif 0 graph_generate_numbers(d,+1)>=m ; numeric d ; @@ -962,24 +935,25 @@ 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 ; @@ -992,10 +966,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 @@ -1010,6 +984,7 @@ 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 : @@ -1027,6 +1002,7 @@ def auto suffix $ = fi enddef ; + string Autoform ; Autoform = "%g"; %vardef autogrid(suffix tx, ty) text w = @@ -1077,11 +1053,12 @@ 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 : @@ -1098,9 +1075,14 @@ 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) = @@ -1126,8 +1108,6 @@ if unknown context_mlib : fi ; -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - % A couple of extensions : % Define a function plotsymbol() returning a picture : 10 different shapes, |