From 85eab5ae6430d439257b3d14de2b819ff734fd1e Mon Sep 17 00:00:00 2001 From: Hans Hagen Date: Sat, 18 Jan 2014 13:23:00 +0100 Subject: beta 2014.01.18 13:23 --- metapost/context/base/mp-grap.mpiv | 268 ++++++++++++++++++++----------------- 1 file changed, 144 insertions(+), 124 deletions(-) (limited to 'metapost') diff --git a/metapost/context/base/mp-grap.mpiv b/metapost/context/base/mp-grap.mpiv index 417bfbe69..6d69c0b1e 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 ' draws picture at each path knot, turns off pen -% Gtemplate. template paths for tick marks and grid lines +% graph_template. 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. -% Gmarks, Gminlog numeric parameters used by auto. +% graph_log_marks[], graph_lin_marks, graph_exp_marks loop text strings used by auto. +% graph_minimum_number_of_marks, graph_log_minimum numeric parameters used by auto. % Autoform is the format string used by autogrid % Autoform_X, Autoform_Y if defined, are used instead @@ -65,22 +65,26 @@ 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 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 +93,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 +120,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 +131,7 @@ vardef graph_Meform(expr x) = enddef ; % Modified from above. + vardef graph_Feform(expr x) = interim warningcheck :=0 ; if x=0 : origin @@ -146,6 +156,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 +211,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 +241,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 +260,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 +283,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 +299,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 +331,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 +350,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 +368,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 +397,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,10 +421,11 @@ 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, @@ -424,11 +437,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 ; @@ -448,13 +461,12 @@ 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 ; @@ -472,9 +484,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 : @@ -486,8 +498,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 +509,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 +525,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 +546,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 +554,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 +568,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 +583,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 +596,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 +660,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 +672,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 +701,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 +725,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 +732,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 +741,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 +755,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 +790,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 -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 +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 +874,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 +883,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 +913,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 +943,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 +962,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 +992,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 +1010,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 +1027,6 @@ def auto suffix $ = fi enddef ; - string Autoform ; Autoform = "%g"; %vardef autogrid(suffix tx, ty) text w = @@ -1053,12 +1077,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 +1098,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 +1126,8 @@ if unknown context_mlib : fi ; +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % A couple of extensions : % Define a function plotsymbol() returning a picture : 10 different shapes, -- cgit v1.2.3