%-------------------------------------------- % % Package pgfplots % % Provides a user-friendly interface to create function plots (normal % plots, semi-logplots and double-logplots). % % It is based on Till Tantau's PGF package. % % Copyright 2007-2012 by Christian Feuersänger. % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by % the Free Software Foundation, either version 3 of the License, or % (at your option) any later version. % % This program is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % % You should have received a copy of the GNU General Public License % along with this program. If not, see . % %-------------------------------------------- % PRECONDITION: % - final axis limits are given in transformed range % - \pgfplots@set@default@size@options has been invoked before % POSTCONDITION: % - the current x,y and z unit vectors are defined properly; % - the fast-access registers are initialised for the axis limits, % - the following macros are assigned: % \pgfplots@[xyz]@veclength % \pgfplots@[xyz]@inverseveclength % \pgfplotspointxaxis % \pgfplotspointyaxis % \pgfplotspointzaxis % \pgfplotspointcenter % \pgfplotspointminminmin % \def\pgfplots@initsizes{% % INIT. % % \pgfplots@xmin@reg=\pgfplots@xmin pt % \pgfplots@xmax@reg=\pgfplots@xmax pt % \pgfplots@ymin@reg=\pgfplots@ymin pt % \pgfplots@ymax@reg=\pgfplots@ymax pt % \ifpgfplots@threedim \pgfplots@zmin@reg=\pgfplots@zmin pt % \pgfplots@zmax@reg=\pgfplots@zmax pt % \fi % %----------------------------------------- % PROCESS THE 'width' and 'height' options %----------------------------------------- % % \pgfkeysgetvalue{/pgfplots/view/az}{\pgfplots@view@az}% \pgfkeysgetvalue{/pgfplots/view/el}{\pgfplots@view@el}% \ifpgfplots@threedim \else \let\pgfplots@view@el=\pgfutil@empty \let\pgfplots@view@az=\pgfutil@empty \fi \ifx\pgfplots@view@az\pgfutil@empty % Note that in presence of "x,y,z" options, the % \pgfplots@set@default@size@options RESETS /pgfplots/view/az. % %\let\pgfplots@rectangle@width=\pgfutil@empty %\let\pgfplots@rectangle@height=\pgfutil@empty \pgfplotsmathvectorfromstring{0,0,1}{default}% \let\pgfplots@view@dir@threedim=\pgfplotsretval % \ifx\pgfplots@x\pgfutil@empty \ifx\pgfplots@width\pgfutil@empty \pgfplots@error{INTERNAL LOGIC ERROR! WIDTH NOT SET}% \fi \fi % \ifx\pgfplots@y\pgfutil@empty \ifx\pgfplots@height\pgfutil@empty \pgfplots@error{INTERNAL LOGIC ERROR! HEIGHT NOT SET}% \fi \fi \ifpgfplots@threedim \def\pgfplots@tmp@Zscale{1}% \else \def\pgfplots@tmp@Zscale{0}% \fi % \pgfplots@initsizes@setunitvector{x}{0}{1}{\pgfplots@tmp@xisaxisparallel}% \pgfplots@initsizes@setunitvector{y}{1}{1}{\pgfplots@tmp@yisaxisparallel}% \pgfplots@initsizes@setunitvector{z}{2}{\pgfplots@tmp@Zscale}{\pgfplots@loc@TMPc}% % \pgfplots@scaling@changewidthheight@for@enlargelimits@by@dimension% % \pgfplots@scale@plotbox@to@widthheight \else % 3D case by `view': \let\pgfplots@x=\pgfutil@empty \let\pgfplots@y=\pgfutil@empty \let\pgfplots@z=\pgfutil@empty \pgfplotssetaxesfromazel{\pgfplots@view@az}{\pgfplots@view@el}{\pgfplots@tmp@xisaxisparallel}% % \pgfplots@scaling@changewidthheight@for@enlargelimits@by@dimension% % \pgfplots@scale@plotbox@to@widthheight \if1\pgfplots@tmp@xisaxisparallel% \def\pgfplots@tmp@yisaxisparallel{1}% \fi \fi \pgfplots@computeunitvectorlengths % \pgfplots@scaling@apply@enlargelimits@by@dimension{x}% \pgfplots@scaling@apply@enlargelimits@by@dimension{y}% \ifpgfplots@threedim \pgfplots@scaling@apply@enlargelimits@by@dimension{z}% \fi % \ifpgfplots@threedim \pgfplotsgetnormalforcurrentview \fi %\message{Pgfplots debug: initialised unit vectors to x=(\the\pgf@xx,\the\pgf@xy), y=(\the\pgf@yx,\the\pgf@yy), z=(\the\pgf@zx,\the\pgf@zy), n = (\pgfplots@view@dir@threedim). Limits are x=\pgfplots@xmin:\pgfplots@xmax, y=\pgfplots@ymin:\pgfplots@ymax^^J }% % \let\pgfplotsmathfloatviewdepthxyz@=\pgfplotsmathfloatviewdepthxyz@infigure \let\pgfplotsmathviewdepthxyz@=\pgfplotsmathviewdepthxyz@infigure % \pgfplotsmath@ifzero{\pgfplots@x@veclength}{\pgfplots@hide@xtrue\pgfplots@shownothingof@xtrue}{}% \pgfplotsmath@ifzero{\pgfplots@y@veclength}{\pgfplots@hide@ytrue\pgfplots@shownothingof@ytrue}{}% \ifpgfplots@threedim \pgfplotsmath@ifzero{\pgfplots@z@veclength}{\pgfplots@hide@ztrue\pgfplots@shownothingof@ztrue}{}% \else \if1\pgfplots@tmp@xisaxisparallel% \if1\pgfplots@tmp@yisaxisparallel% % Optimize for axis-parallel case! % puh. Did not make any measureable difference!? Ok... \let\pgfplotsqpointxy=\pgfplotsqpointxy@orthogonal \fi \fi \fi } % Defines \pgfmathresult to be the desired width without axis labels. % \def\pgfplots@initsizes@get@width@withoutlabels{% \pgfplots@initsizes@handle@label@const{\pgfplots@width}{45pt}{width}% } % Defines \pgfmathresult to be the desired height without axis labels. \def\pgfplots@initsizes@get@height@withoutlabels{% \pgfplots@initsizes@handle@label@const{\pgfplots@height}{45pt}{height}% } \def\pgfplots@initsizes@handle@label@const#1#2#3{% \begingroup \pgf@xa=#1\relax % EXPECTED WIDTH = X = \pgfplots@width % ACTUAL WIDTH = c + x * (xmax-xmin) % where c is a CONSTANT (for the axis labels/tick labels). % -> \pgfplots@tmpXscale = (X - c) / (x *(xmax-xmin)) % % \pgf@xa := X-c: \ifpgfplots@scale@only@axis \else \advance\pgf@xa by-#2 % FIXME determine 'c' correctly! \fi \ifdim\pgf@xa<0pt \pgfplots@error{Error: Plot #3 `#1' is too small. This cannot be implemented while maintaining constant size for labels. Sorry, label sizes are only approximate. You will need to adjust your #3.}% \pgf@xa=0pt \fi \edef\pgfmathresult{\the\pgf@xa}% \pgfmath@smuggleone\pgfmathresult \endgroup }% % #1: axis \def\pgfplots@axis@apply@post@scale#1{% % \pgfkeysgetvalue{/pgfplots/#1 post scale}\pgfplots@loc@TMPd \ifx\pgfplots@loc@TMPd\pgfutil@empty \else \pgfmathparse{\csname pgfplots@target@unit@scale@#1x\endcsname*\pgfplots@loc@TMPd}% \expandafter\let\csname pgfplots@target@unit@scale@#1x\endcsname=\pgfmathresult % \pgfmathparse{\csname pgfplots@target@unit@scale@#1y\endcsname*\pgfplots@loc@TMPd}% \expandafter\let\csname pgfplots@target@unit@scale@#1y\endcsname=\pgfmathresult \fi } % Takes azimuth (horizontal angle) '#1' and elongation (vertical % angle) '#2' (both in degrees) and computes % x,y and z vectors which define the view in the direction % defined by '#1' and '#2'. % % 'azimuth' means a rotation around the viewport's x axis. 'elongation' means % a rotation around the original coordinate system's z axis. % % The method works by computing % Az = [ cos(azimuth) -sin(azimuth) 0; ... % sin(azimuth) cos(azimuth) 0; ... % 0 0 1 ]; % % % Ax = [ 1 0 0; ... % 0 cos(elevation) -sin(elevation) ;... % 0 sin(elevation) cos(elevation) ]; % % v= Ax * Az; % = [ ... % cosaz -sinaz cosel sinaz sinel; ... % sinaz cosaz cosel -sinel cosaz; ... % 0 sinel cosel ]; % % Then, we use the rotated XZ plane as viewport, that means % xvec = v * [1 0 0]' = % zvec = v * [0 0 1]' = % and we define the projection onto the twodimensional surface % spanned by 'xvec' and 'zvec' as % P( q ) = [ q^T xvec, q^T zvec ]' % for q in R^3. % As a consequence, we compute the three unit vectors as % x = P( [1 0 0] ) % = [ cosaz, sinaz sinel ]' % y = P( [0 1 0] ) % = [ sinaz, -sinel cosaz ]' % z = P( [0 0 1] ) % = [ 0, cosel]' % % Furthermore, the 3D view vector which points into the direction of the view % is % n = v * [0 1 0 ]' = = [-sinaz cosel, cosaz cosel, sinel]' % because the normal view point was the XZ plane with y as its normal % vector. % The 3D vector n is returned by this routine as well - it is % necessary for some kind of z buffering (determining what is % foreground and what is background). % % INPUT: % - #1 : azimuth ("yaw") % - #2 : elevation ("pitch") % OUTPUT: % - #3 : a macro which will be set to '1' if and only if % the viewport is the standard XY axis (i.e. azimuth=0, elevation=90). % - [xyz] vectors, % \pgfplots@view@dir@threedim will contain the three components % of 'n' (without the suffix 'pt', but in units of 'pt') (see % \pgfplotsmathvectorfromstring). \def\pgfplotssetaxesfromazel#1#2#3{% \begingroup \pgfmathparse{#1}% \let\pgfplots@az=\pgfmathresult \pgfmathparse{#2}% \edef\pgfplots@el{-\pgfmathresult}% \pgfmathsin@{\pgfplots@az}% \let\sinaz=\pgfmathresult \pgfmathcos@{\pgfplots@az}% \let\cosaz=\pgfmathresult \pgfmathsin@{\pgfplots@el}% \let\sinel=\pgfmathresult \pgfmathcos@{\pgfplots@el}% \let\cosel=\pgfmathresult % x: \pgfmathmultiply@{\sinaz}{\sinel}% \xdef\pgfplots@glob@TMPa{\noexpand\pgfqpoint{\cosaz pt}{\pgfmathresult pt}}% % y: \pgfmathmultiply@{-\sinel}{\cosaz}% \xdef\pgfplots@glob@TMPb{\noexpand\pgfqpoint{\sinaz pt}{\pgfmathresult pt}}% % z: \xdef\pgfplots@glob@TMPc{\noexpand\pgfqpoint{0pt}{\cosel pt}}% % \pgfkeysgetvalue{/pgfplots/x dir/value}\pgfplots@loc@dirvalue@x \pgfkeysgetvalue{/pgfplots/y dir/value}\pgfplots@loc@dirvalue@y \pgfkeysgetvalue{/pgfplots/z dir/value}\pgfplots@loc@dirvalue@z \if r\pgfplots@loc@dirvalue@x \t@pgfplots@toka=\expandafter{\pgfplots@glob@TMPa}% \xdef\pgfplots@glob@TMPa{\noexpand\pgfqpointscale{-1}{\the\t@pgfplots@toka}}% \fi \if r\pgfplots@loc@dirvalue@y \t@pgfplots@toka=\expandafter{\pgfplots@glob@TMPb}% \xdef\pgfplots@glob@TMPb{\noexpand\pgfqpointscale{-1}{\the\t@pgfplots@toka}}% \fi \if r\pgfplots@loc@dirvalue@z \t@pgfplots@toka=\expandafter{\pgfplots@glob@TMPc}% \xdef\pgfplots@glob@TMPc{\noexpand\pgfqpointscale{-1}{\the\t@pgfplots@toka}}% \fi % % Process 'plot box ratio': \def\pgfplots@extract@plot@box@ratio##1##2##3##4\pgfplots@EOI{% \pgfmathparse{##1}\let\pgfplots@plotboxratio@x=\pgfmathresult \pgfmathparse{##2}\let\pgfplots@plotboxratio@y=\pgfmathresult \pgfmathparse{##3}\let\pgfplots@plotboxratio@z=\pgfmathresult }% \def\pgfplots@extract@plot@box@ratio@spaces##1 ##2 ##3 ##4\pgfplots@EOI{% \pgfplots@extract@plot@box@ratio{##1}{##2}{##3}{##4}\pgfplots@EOI }% \pgfkeysgetvalue{/pgfplots/plot box ratio}\pgfplots@loc@TMPa % Auto-determine input format which is either '{x}{y}{z}' or 'x y z' \def\pgfplots@loc@TMPb{% \pgfutil@ifnextchar\bgroup{% \pgfplots@loc@tmptrue \pgfplots@gobble@until@EOI }{% \pgfplots@loc@tmpfalse \pgfplots@gobble@until@EOI }% }% \expandafter\pgfplots@loc@TMPb\pgfplots@loc@TMPa\pgfplots@EOI \ifpgfplots@loc@tmp % Ah- braces format. \edef\pgfplots@loc@TMPa{\pgfplots@loc@TMPa{1}{1}{1}}% \expandafter\pgfplots@extract@plot@box@ratio\pgfplots@loc@TMPa\pgfplots@EOI \else % Ah- space-separated \edef\pgfplots@loc@TMPa{\pgfplots@loc@TMPa\space 1 1 1}% \expandafter\pgfplots@extract@plot@box@ratio@spaces\pgfplots@loc@TMPa\pgfplots@EOI \fi % % process it: \ifdim\pgfplots@plotboxratio@x pt=1pt \else \t@pgfplots@toka=\expandafter{\pgfplots@glob@TMPa}% \xdef\pgfplots@glob@TMPa{\noexpand\pgfqpointscale{\pgfplots@plotboxratio@x}{\the\t@pgfplots@toka}}% \fi \ifdim\pgfplots@plotboxratio@y pt=1pt \else \t@pgfplots@toka=\expandafter{\pgfplots@glob@TMPb}% \xdef\pgfplots@glob@TMPb{\noexpand\pgfqpointscale{\pgfplots@plotboxratio@y}{\the\t@pgfplots@toka}}% \fi \ifdim\pgfplots@plotboxratio@z pt=1pt \else \t@pgfplots@toka=\expandafter{\pgfplots@glob@TMPc}% \xdef\pgfplots@glob@TMPc{\noexpand\pgfqpointscale{\pgfplots@plotboxratio@z}{\the\t@pgfplots@toka}}% \fi % % n (3D!) \pgfmathmultiply@{-\sinaz}{\cosel}% \let\pgfmathresultNx=\pgfmathresult \pgfmathmultiply@{\cosaz}{\cosel}% \xdef\pgfplots@glob@TMPd{{\pgfmathresultNx}{\pgfmathresult}{\sinel}}% \endgroup %\message{Setting x,y and z from {#1}{#2} to^^J x = \meaning\pgfplots@glob@TMPa,^^J y = \meaning\pgfplots@glob@TMPb,^^J z = \meaning\pgfplots@glob@TMPc,^^J n = \pgfplots@glob@TMPd.^^J}% \pgfsetxvec{\pgfplots@glob@TMPa}% \pgfsetyvec{\pgfplots@glob@TMPb}% \pgfsetzvec{\pgfplots@glob@TMPc}% \def\pgfplots@loc@TMPa##1##2##3{% \pgfplotsmathvectorfromstring{##1,##2,##3}{default}% \let\pgfplots@view@dir@threedim=\pgfplotsretval }% \expandafter\pgfplots@loc@TMPa\pgfplots@glob@TMPd\relax \def#3{0}% }% % Takes the current plot box, defined by the actual PGF x,y and z unit % vectors, and re-scales it such that it fits into the % width and height of the axis (as they have been provided by the % user). % % @see \pgfplots@scale@axisbox@to@widthheight % @see\pgfplots@scaleaxes@to@BB \def\pgfplots@scale@plotbox@to@widthheight{% \pgfplots@initsizes@get@width@withoutlabels \let\pgfplots@loc@TMPa=\pgfmathresult \pgfplots@initsizes@get@height@withoutlabels % \edef\pgfplots@loc@TMPa{{\pgfplots@loc@TMPa}{\pgfmathresult}}% \expandafter\pgfplots@scaleaxes@to@BB\pgfplots@loc@TMPa } % Takes the current PGF x,y and z unit vectors and scales them such % that the bounding box of the final image has width #1 and height #2. % % The relative length of the input vectors is important for the 3D case: it % will be scaled as-is. % % PRECONDITION % - the x, y and z unit vectors have been set to the proper % DIRECTIONS. Their relative vector lengths are set-up properly % (i.e. y is twice as large as x and half as large as z or so). % - the \ifpgfplots@threedim boolean is set. % - the data limits have been initialised and transformed according % to the data transformation. % - the data transformation has ONLY been applied to the axis limits % (not other axis inputs). It may be changed by this method. % % POSTCONDITION % - the unit vectors have been re-scaled such that the final plot % has the desired dimensions. % - the @veclength and @inverseveclength have been initialized \def\pgfplots@scaleaxes@to@BB#1#2{% \if0\pgfplots@scale@mode@choice % scale mode=auto \def\pgfplots@scale@mode@choice{2}% stretch to fill \fi \pgfplots@scaleaxes@to@BB@{#1}{#2}% % NOTE: we have not yet computed the lengths of unit vectors. In % addition, we have not yet updated the normal vector. }% % DEPRECATED: \def\pgfplots@rescale@view@dir{% \expandafter\ifx\csname pgfplots@view@dir@threedim\endcsname\relax \else % At this point, we ALREADY HAVE a normal vector. However, it % might be skewed due to the scaling. % % -> recompute normal vector. In earlier versions, I tried to % rescale it - but that was too complicated (for me). This % here produces correct results, and it is a correct approach % anyway. \pgfplotsgetnormalforcurrentview \fi }% % \pgfplots@BB@for@plotbox@get@unit@scales@for@limits{#1}{#2}{#3}: % a helper tool which computes individual unit vector scales in order % to respect the limits. % % This method ignores width/height; its purpose is only to make sure % that [xmin,xmax] fits into the CURRENT plot box. % % In this context, each unit vector is supposed to be scaled such that % width/height fit if xmin=0 and xmax=1. % % #1 [output] a macro name which will contain the INVERSE scale for x % #2 [output] a macro name which will contain the INVERSE scale for y % #3 [output] a macro name which will contain the INVERSE scale for z % \def\pgfplots@BB@for@plotbox@get@unit@scales@for@limits#1#2#3{% \if1\b@pgfplots@plotbox@xisunit % Consequently, we have to multiply with 1/(max-min): % compute 1/(xmax - xmin) in float for more recent versions (see /pgfplots/compat/scaling). % I observed that it is much more accurate \pgfmathsubtract@{\pgfplots@xmax}{\pgfplots@xmin}% \else \def\pgfmathresult{1}% \fi \let#1=\pgfmathresult % \if1\b@pgfplots@plotbox@yisunit \pgfmathsubtract@{\pgfplots@ymax}{\pgfplots@ymin}% \else \def\pgfmathresult{1}% \fi \let#2=\pgfmathresult % \ifpgfplots@threedim \if1\b@pgfplots@plotbox@zisunit \pgfmathsubtract@{\pgfplots@zmax}{\pgfplots@zmin}% \else \def\pgfmathresult{1}% \fi \else \def\pgfmathresult{1}% \fi \let#3=\pgfmathresult }% \def\pgfplots@BB@for@plotbox{% \ifpgfplots@threedim \pgfpathmoveto{\pgfqpointxyz\pgfplots@plotbox@xmin\pgfplots@plotbox@ymin\pgfplots@plotbox@zmin}% \pgfpathmoveto{\pgfqpointxyz\pgfplots@plotbox@xmin\pgfplots@plotbox@ymin\pgfplots@plotbox@zmax}% \pgfpathmoveto{\pgfqpointxyz\pgfplots@plotbox@xmin\pgfplots@plotbox@ymax\pgfplots@plotbox@zmin}% \pgfpathmoveto{\pgfqpointxyz\pgfplots@plotbox@xmin\pgfplots@plotbox@ymax\pgfplots@plotbox@zmax}% \pgfpathmoveto{\pgfqpointxyz\pgfplots@plotbox@xmax\pgfplots@plotbox@ymin\pgfplots@plotbox@zmin}% \pgfpathmoveto{\pgfqpointxyz\pgfplots@plotbox@xmax\pgfplots@plotbox@ymin\pgfplots@plotbox@zmax}% \pgfpathmoveto{\pgfqpointxyz\pgfplots@plotbox@xmax\pgfplots@plotbox@ymax\pgfplots@plotbox@zmin}% \pgfpathmoveto{\pgfqpointxyz\pgfplots@plotbox@xmax\pgfplots@plotbox@ymax\pgfplots@plotbox@zmax}% \else \pgfpathmoveto{\pgfqpointxy\pgfplots@plotbox@xmin\pgfplots@plotbox@ymin}% \pgfpathmoveto{\pgfqpointxy\pgfplots@plotbox@xmin\pgfplots@plotbox@ymax}% \pgfpathmoveto{\pgfqpointxy\pgfplots@plotbox@xmax\pgfplots@plotbox@ymin}% \pgfpathmoveto{\pgfqpointxy\pgfplots@plotbox@xmax\pgfplots@plotbox@ymax}% \fi }% % Returns width and height of the current plot box % (the path produced by \pgfplots@BB@for@plotbox). % % PRECONDITION: \pgfplots@BB@for@plotbox is defined to produce a path % for the plot box % % POSTCONDITION: \pgfplotsretval contains the with and % \pgfplotsretvalb contains the height \def\pgfplots@get@dimension@of@BB{% \begingroup \pgfinterruptboundingbox % % the result of this call will be used to scale to target % dimensions. If we omit \pgftransformreset here, we might % accidentally UNDO the PGF transformation matrix (compare by % writing \tikzpicture[scale=0.5] before the axis). \pgftransformreset % % STEP 1: compute the bounding box for the plot box. \pgfplots@BB@for@plotbox % % TMPa = width \pgf@xa=\pgf@pathmaxx \advance\pgf@xa by-\pgf@pathminx % TMPb = height \pgf@xb=\pgf@pathmaxy \advance\pgf@xb by-\pgf@pathminy \xdef\pgfplots@glob@TMPa{% \def\noexpand\pgfplotsretval{\the\pgf@xa}% \def\noexpand\pgfplotsretvalb{\the\pgf@xb}% }% \pgfusepath{discard}% \endpgfinterruptboundingbox \endgroup \pgfplots@glob@TMPa }% \def\pgfplots@scaleaxes@to@BB@prepare@plotbox@limits{% \def\b@pgfplots@rescale@x{1}% \def\b@pgfplots@rescale@y{1}% \def\b@pgfplots@rescale@z{1}% % \pgfplots@scaleaxes@to@BB@prepare@plotbox@limits@ x% \pgfplots@scaleaxes@to@BB@prepare@plotbox@limits@ y% \pgfplots@scaleaxes@to@BB@prepare@plotbox@limits@ z% }% \def\pgfplots@scaleaxes@to@BB@prepare@plotbox@limits@#1{% \expandafter\ifx\csname pgfplots@#1\endcsname\pgfutil@empty % Ah - we have no unit vector in this direction. \expandafter\def\csname pgfplots@plotbox@#1min\endcsname{0}% \expandafter\def\csname pgfplots@plotbox@#1max\endcsname{1}% \expandafter\def\csname b@pgfplots@plotbox@#1isunit\endcsname{1}% \else % we have a unit vector... prepare for limits. Note that the % unit vector has been prepared for data scaling already. \pgfutil@namelet{pgfplots@plotbox@#1min}{pgfplots@#1min}% \pgfutil@namelet{pgfplots@plotbox@#1max}{pgfplots@#1max}% \expandafter\def\csname b@pgfplots@plotbox@#1isunit\endcsname{0}% \if2\pgfplots@scale@mode@choice % scale mode=stretch to fill % do NOT rescale unit vectors for stretch to fill : \expandafter\def\csname b@pgfplots@rescale@#1\endcsname{0}% \fi \fi \expandafter\def\csname b@pgfplots@unitvec@is@zero@#1\endcsname{0}% \ifdim\csname pgf@#1x\endcsname=0pt % \ifdim\csname pgf@#1y\endcsname=0pt % \expandafter\def\csname b@pgfplots@unitvec@is@zero@#1\endcsname{1}% \fi \fi } \def\pgfplots@scaleaxes@to@BB@#1#2{% \begingroup %\message{SCALING: scale mode choice = \pgfplots@scale@mode@choice^^J}% % \pgfplots@scaleaxes@to@BB@prepare@plotbox@limits \def\pgfplots@target@limitrescale@x{1}% \def\pgfplots@target@limitrescale@y{1}% \def\pgfplots@target@limitrescale@z{1}% \if1\pgfplots@scale@mode@choice % scale mode=none \def\xscale{1}% \def\yscale{1}% \def\pgfplots@target@unit@scale@inv@x{1}% \def\pgfplots@target@unit@scale@inv@y{1}% \def\pgfplots@target@unit@scale@inv@z{1}% \else % % This here CAN cause anisotropic (different) scaling factors. \pgfplots@BB@for@plotbox@get@unit@scales@for@limits {\pgfplots@target@unit@scale@inv@x} {\pgfplots@target@unit@scale@inv@y} {\pgfplots@target@unit@scale@inv@z}% % %\message{got scales to fit limits into BB: x=1/\pgfplots@target@unit@scale@inv@x, y=1/\pgfplots@target@unit@scale@inv@y, z=1/\pgfplots@target@unit@scale@inv@z^^J}% % \if3\pgfplots@scale@mode@choice % scale mode=scale uniformly % % We need to recompensate in case the previous method chose % different unit scaling scalings: \pgfplots@BB@for@plotbox@get@unit@scales@compensated@axis@limits {\pgfplots@target@unit@scale@inv@x} {\pgfplots@target@unit@scale@inv@y} {\pgfplots@target@unit@scale@inv@z} {\pgfplots@target@limitrescale@x}{\pgfplots@target@limitrescale@y}{\pgfplots@target@limitrescale@z}% % %\pgfplots@BB@update@cumulative@limit@compensations \fi %\message{adjusted scales for 'scale mode': x=1/\pgfplots@target@unit@scale@inv@x, y=1/\pgfplots@target@unit@scale@inv@y, z=1/\pgfplots@target@unit@scale@inv@z; ^^J axis limit componsation scales x=\pgfplots@target@limitrescale@x, y=\pgfplots@target@limitrescale@y, z=\pgfplots@target@limitrescale@z^^J}% % % ATTENTION: this MODIFIES \pgfplots@target@limitrescale@x and its % variants directly - and it needs the input values. \pgfplots@get@scale@horiz@and@vert {#1}% {#2}% {\xscale}% {\yscale}% yscale {\pgfplots@target@limitrescale@x}% {\pgfplots@target@limitrescale@y}% {\pgfplots@target@limitrescale@z}% %\message{Got W/H scale for all x components: \xscale; for all y components: \xscale; ^^J axis limit componsation scales x=1/\pgfplots@target@limitrescale@x, y=1/\pgfplots@target@limitrescale@y, z=1/\pgfplots@target@limitrescale@z^^J}% % Ok, we know the W,H scalings now. % % % \pgfplots@apply@unit@ratio {\pgfplots@target@unit@scale@inv@x} {\pgfplots@target@unit@scale@inv@y} {\pgfplots@target@unit@scale@inv@z} {\pgfplots@target@limitrescale@x@}{\pgfplots@target@limitrescale@y@}{\pgfplots@target@limitrescale@z@}% \pgfplots@BB@update@cumulative@limit@compensations % %\message{adjusted scales for 'unit vector ratio': x=1/\pgfplots@target@unit@scale@inv@x, y=1/\pgfplots@target@unit@scale@inv@y, z=1/\pgfplots@target@unit@scale@inv@z; ^^J axis limit componsation scales x=\pgfplots@target@limitrescale@x, y=\pgfplots@target@limitrescale@y, z=\pgfplots@target@limitrescale@z^^J}% \fi % % \pgfplots@scaling@minimize@limitrescale% % % \pgfplots@scaling@adjust@datascaling% %\message{adjusted scales for data scale trafo: x=1/\pgfplots@target@unit@scale@inv@x, y=1/\pgfplots@target@unit@scale@inv@y, z=1/\pgfplots@target@unit@scale@inv@z; ^^J axis limit componsation scales x=\pgfplots@target@limitrescale@x, y=\pgfplots@target@limitrescale@y, z=\pgfplots@target@limitrescale@z;^^J data scale trafo exponents x=\pgfplots@target@datascaletrafo@x@exponent@old -> \pgfplots@target@datascaletrafo@x@exponent, y=\pgfplots@target@datascaletrafo@y@exponent@old -> \pgfplots@target@datascaletrafo@y@exponent, z=\pgfplots@target@datascaletrafo@z@exponent@old -> \pgfplots@target@datascaletrafo@z@exponent^^J}% % \pgfplots@scaling@compute@final@scales% {\xscale}{\yscale}% {\pgfplots@target@unit@scale@inv@x}% {\pgfplots@target@unit@scale@inv@y}% {\pgfplots@target@unit@scale@inv@z}% % \pgfplots@axis@apply@post@scale{x}% \pgfplots@axis@apply@post@scale{y}% \ifpgfplots@threedim \pgfplots@axis@apply@post@scale{z}% \fi % % and finally, resize limits appropriately and add all cumulative limit compensations: \xdef\pgfplots@glob@TMPa{% % \pgf@xx=\pgfplots@target@unit@scale@xx\pgf@xx \pgf@xy=\pgfplots@target@unit@scale@xy\pgf@xy % \pgf@yx=\pgfplots@target@unit@scale@yx\pgf@yx \pgf@yy=\pgfplots@target@unit@scale@yy\pgf@yy % \ifpgfplots@threedim \pgf@zx=\pgfplots@target@unit@scale@zx\pgf@zx \pgf@zy=\pgfplots@target@unit@scale@zy\pgf@zy \fi % \noexpand\pgfplots@apply@datascaletrafo@change@{x}{\pgfplots@target@datascaletrafo@x@exponent}% \noexpand\pgfplots@apply@datascaletrafo@change@{y}{\pgfplots@target@datascaletrafo@y@exponent}% \noexpand\pgfplots@apply@datascaletrafo@change@{z}{\pgfplots@target@datascaletrafo@z@exponent}% % \noexpand\pgfplots@apply@unit@vector@rescale@keep@size{x}{\pgfplots@target@limitrescale@x}% \noexpand\pgfplots@apply@unit@vector@rescale@keep@size{y}{\pgfplots@target@limitrescale@y}% \noexpand\pgfplots@apply@unit@vector@rescale@keep@size{z}{\pgfplots@target@limitrescale@z}% % \noexpand\pgfplots@notify@final@scalings{% x unit scale=\pgfplots@target@unit@scale@x,% y unit scale=\pgfplots@target@unit@scale@y,% z unit scale=\pgfplots@target@unit@scale@z,% x datatrafo exponent=\pgfplots@target@datascaletrafo@x@exponent,% y datatrafo exponent=\pgfplots@target@datascaletrafo@y@exponent,% z datatrafo exponent=\pgfplots@target@datascaletrafo@z@exponent,% x limit rescale=\pgfplots@target@limitrescale@x,% y limit rescale=\pgfplots@target@limitrescale@y,% z limit rescale=\pgfplots@target@limitrescale@z,% }% }% \endgroup \pgfplots@glob@TMPa }% % Checks for the case the ALL (visible) limit compensation scales are % bigger than one (for example x = 1.22, y = 2). In such a case, we % want to MINIMIZE the rescaling. This can happen if unit vector ratio % is active. % % In our example, we want to use limit rescaling factors x = 1, y = 2/1.22 % and, consequently, unit rescaling factors x *= 1.22, y *= 1.22 . % % This method checks for the case and applies the rescaling if % necessary. % \def\pgfplots@scaling@minimize@limitrescale{% % boolean allLimitScalesAreBiggerThanOne; \pgfplots@loc@tmptrue \if0\b@pgfplots@unitvec@is@zero@x \ifdim\pgfplots@target@limitrescale@x pt<1.002pt % \pgfplots@loc@tmpfalse \fi \fi \if0\b@pgfplots@unitvec@is@zero@y \ifdim\pgfplots@target@limitrescale@y pt<1.002pt % \pgfplots@loc@tmpfalse \fi \fi \if0\b@pgfplots@unitvec@is@zero@z \ifdim\pgfplots@target@limitrescale@z pt<1.002pt % \pgfplots@loc@tmpfalse \fi \fi % \ifpgfplots@loc@tmp \begingroup % Ah -- all non-vanishing limit rescaling factors are BIGGER % THAN ONE. % In this case, we can save some rescalings! % % Search for the smallest rescaling factor. \let\pgfplots@smallest=\pgf@x \pgfplots@smallest=16000pt % \def\pgfplots@smallest@arg{}% \if0\b@pgfplots@unitvec@is@zero@x \pgf@xa=\pgfplots@target@limitrescale@x pt % \ifdim\pgf@xa<\pgfplots@smallest% \pgfplots@smallest=\pgf@xa \def\pgfplots@smallest@arg{x}% \fi \fi \if0\b@pgfplots@unitvec@is@zero@y \pgf@xa=\pgfplots@target@limitrescale@y pt % \ifdim\pgf@xa<\pgfplots@smallest% \pgfplots@smallest=\pgf@xa \def\pgfplots@smallest@arg{y}% \fi \fi \if0\b@pgfplots@unitvec@is@zero@z \pgf@xa=\pgfplots@target@limitrescale@z pt % \ifdim\pgf@xa<\pgfplots@smallest% \pgfplots@smallest=\pgf@xa \def\pgfplots@smallest@arg{z}% \fi \fi % % OK. We have the smallest scaling factor. It is > 1. \pgfplotscoordmath{default}{parsenumber}{\pgfplots@target@limitrescale@x}% \let\pgfplots@target@limitrescale@x=\pgfmathresult \pgfplotscoordmath{default}{parsenumber}{\pgfplots@target@limitrescale@y}% \let\pgfplots@target@limitrescale@y=\pgfmathresult % % \pgfplotscoordmath{default}{parsenumber}{\pgfplots@target@unit@scale@inv@x}% \let\pgfplots@target@unit@scale@inv@x=\pgfmathresult \pgfplotscoordmath{default}{parsenumber}{\pgfplots@target@unit@scale@inv@y}% \let\pgfplots@target@unit@scale@inv@y=\pgfmathresult % \if0\b@pgfplots@unitvec@is@zero@z \pgfplotscoordmath{default}{parsenumber}{\pgfplots@target@limitrescale@z}% \let\pgfplots@target@limitrescale@z=\pgfmathresult \pgfplotscoordmath{default}{parsenumber}{\pgfplots@target@unit@scale@inv@z}% \let\pgfplots@target@unit@scale@inv@z=\pgfmathresult \fi % \pgfplotscoordmath{default}{op}{reciprocal}{{\csname pgfplots@target@limitrescale@\pgfplots@smallest@arg\endcsname}}% \let\scale=\pgfmathresult % \pgfplotsforeachentryinCSV\value{% \pgfplots@target@unit@scale@inv@x,% \pgfplots@target@unit@scale@inv@y,% \pgfplots@target@limitrescale@x,% \pgfplots@target@limitrescale@y% }{% \pgfplotscoordmath{default}{op}{multiply}{{\scale}{\value}}% \pgfplotscoordmath{default}{tofixed}{\pgfmathresult}% \expandafter\let\value=\pgfmathresult }% \if0\b@pgfplots@unitvec@is@zero@z \pgfplotsforeachentryinCSV\value{% \pgfplots@target@unit@scale@inv@z,% \pgfplots@target@limitrescale@z% }{% \pgfplotscoordmath{default}{op}{multiply}{{\scale}{\value}}% \pgfplotscoordmath{default}{tofixed}{\pgfmathresult}% \expandafter\let\value=\pgfmathresult }% \fi % \xdef\pgfplots@glob@TMPa{% \noexpand\def\noexpand\pgfplots@target@unit@scale@inv@x{\pgfplots@target@unit@scale@inv@x}% \noexpand\def\noexpand\pgfplots@target@unit@scale@inv@y{\pgfplots@target@unit@scale@inv@y}% \noexpand\def\noexpand\pgfplots@target@unit@scale@inv@z{\pgfplots@target@unit@scale@inv@z}% \noexpand\def\noexpand\pgfplots@target@limitrescale@x{\pgfplots@target@limitrescale@x}% \noexpand\def\noexpand\pgfplots@target@limitrescale@y{\pgfplots@target@limitrescale@y}% \noexpand\def\noexpand\pgfplots@target@limitrescale@z{\pgfplots@target@limitrescale@z}% }% \endgroup \pgfplots@glob@TMPa % %\message{adjusted scales by minimizing common scaling factors: x=1/\pgfplots@target@unit@scale@inv@x, y=1/\pgfplots@target@unit@scale@inv@y, z=1/\pgfplots@target@unit@scale@inv@z; ^^J axis limit componsation scales x=\pgfplots@target@limitrescale@x, y=\pgfplots@target@limitrescale@y, z=\pgfplots@target@limitrescale@z;^^J}% \fi }% % Defines % \pgfplots@target@unit@scale@xx % \pgfplots@target@unit@scale@xy % \pgfplots@target@unit@scale@yx % \pgfplots@target@unit@scale@yy % \pgfplots@target@unit@scale@zx % \pgfplots@target@unit@scale@zy % % % \pgfplots@target@unit@scale@x % \pgfplots@target@unit@scale@y % \pgfplots@target@unit@scale@z % by combining the input args. % % #1: the scale to be applied to ALL x components % #2: the scale to be applied to ALL y components % #3: the scale to be applied to x unit % #4: the scale to be applied to y unit % #5: the scale to be applied to z unit \def\pgfplots@scaling@compute@final@scales#1#2#3#4#5{% % ##1: the axis (x,y,or z) % ##2: the horizontal scale % ##3: the vertical scale % ##4: the inverse unit scale for this axis \def\pgfplots@loc@TMPa##1##2##3##4{% \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath}{parsenumber}{##2}% \let\xscale@@=\pgfmathresult \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath}{parsenumber}{##3}% \let\yscale@@=\pgfmathresult \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath}{parsenumber}{##4}% \let\unitscale@inv@@=\pgfmathresult % % NOTE : it *would* be more efficient to use % 1/\unitscale@inv@@ in the routines above. BUT THAT IS NOT BACKWARDS COMPATIBLE. % Leave it this way! \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath}{op}{reciprocal}{{\unitscale@inv@@}}% \let\unitscale@@=\pgfmathresult \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath}{tofixed}{\pgfmathresult}% \expandafter\let\csname pgfplots@target@unit@scale@##1\endcsname=\pgfmathresult % % \ifx\pgfplots@compat@scaling@coordmath@final\pgfplots@compat@scaling@coordmath \else % backwards compatibility is such a burden.... :-( % % earlier versions relied on TeX's dimen arithmetics to % multiply the final scales. Make sure we do the same - % rounding errors on unit vectors are instable, i.e. the % errors add up considerably. \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath@final}{parsenumber}{\xscale@@}% \let\xscale@@=\pgfmathresult \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath@final}{parsenumber}{\yscale@@}% \let\yscale@@=\pgfmathresult \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath@final}{parsenumber}{\unitscale@@}% \let\unitscale@@=\pgfmathresult \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath@final}{parsenumber}{\unitscale@inv@@}% \let\unitscale@inv@@=\pgfmathresult \fi % \ifpgfplots@threedim % backw. compatibility: this is how it used to be in 3d % axes: \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath@final}{op}{multiply}{{\xscale@@}{\unitscale@@}}% \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath@final}{tofixed}{\pgfmathresult}% \expandafter\let\csname pgfplots@target@unit@scale@##1x\endcsname=\pgfmathresult % \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath@final}{op}{multiply}{{\yscale@@}{\unitscale@@}}% \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath@final}{tofixed}{\pgfmathresult}% \expandafter\let\csname pgfplots@target@unit@scale@##1y\endcsname=\pgfmathresult \else % backw. compatibility: 2d axes used divide in earlier % versions, not reciprocal. Believe it or not; for % \pgfplots@compat@scaling@coordmath=pgfbasic, it makes a % visible difference of about 2-3pt in the complete figure % size. \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath@final}{op}{divide}{{\xscale@@}{\unitscale@inv@@}}% \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath@final}{tofixed}{\pgfmathresult}% \expandafter\let\csname pgfplots@target@unit@scale@##1x\endcsname=\pgfmathresult % \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath@final}{op}{divide}{{\yscale@@}{\unitscale@inv@@}}% \pgfplotscoordmath{\pgfplots@compat@scaling@coordmath@final}{tofixed}{\pgfmathresult}% \expandafter\let\csname pgfplots@target@unit@scale@##1y\endcsname=\pgfmathresult \fi % }% \if1\b@pgfplots@rescale@x \pgfplots@loc@TMPa{x}{\xscale}{\yscale}{#3}% \else \pgfplots@loc@TMPa{x}{1}{1}{#3}% \fi % \if1\b@pgfplots@rescale@y \pgfplots@loc@TMPa{y}{\xscale}{\yscale}{#4}% \else \pgfplots@loc@TMPa{y}{1}{1}{#4}% \fi % \ifpgfplots@threedim \if1\b@pgfplots@rescale@z \pgfplots@loc@TMPa{z}{\xscale}{\yscale}{#5}% \else \pgfplots@loc@TMPa{z}{1}{1}{#5}% \fi \else \def\pgfplots@target@unit@scale@z{0}% \def\pgfplots@target@unit@scale@zx{0}% \def\pgfplots@target@unit@scale@zy{0}% \def\pgfplots@target@unit@scale@inv@z{inf}% \fi % }% \def\pgfplots@notify@final@scalings#1{% \pgfkeys{/pgfplots/scaling/.cd, .unknown/.code={% %\message{setting key '\pgfkeyscurrentkey' to {##1}^^J} \pgfkeyssetvalue{\pgfkeyscurrentkey}{##1}% }, #1% }% }% % #1: either x,y, or z % #2: the new exponent \def\pgfplots@apply@datascaletrafo@change@#1#2{% \pgfplots@if{pgfplots@apply@datatrafo@#1}{% \pgfplotscoordmath{#1}{datascaletrafo get params}% \edef\pgfplots@loc@TMPa{\expandafter\pgfutil@firstoftwo\pgfmathresult}% \edef\pgfplots@loc@TMPb{#2}% \ifx\pgfplots@loc@TMPa\pgfplots@loc@TMPb % ok; the data scale trafo did not change at all - we % still have the same exponent. \else % Ah - we have a new data scale trafo! \pgfplotscoordmath{#1}{datascaletrafo inverse}{\csname pgfplots@#1min\endcsname}% \let\pgfplots@loc@TMPa=\pgfmathresult \pgfplotscoordmath{#1}{datascaletrafo inverse}{\csname pgfplots@#1max\endcsname}% \let\pgfplots@loc@TMPb=\pgfmathresult % % first: determine the optimal shift (which is the % transformed lower limit): \pgfplotscoordmath{#1}{datascaletrafo set params}{#2}{0}% \pgfplotscoordmath{#1}{datascaletrafo}{\pgfplots@loc@TMPa}% % % ok, finalize the data trafo: \pgfplotscoordmath{#1}{datascaletrafo set params}{#2}{\pgfmathresult}% % % ... and recompute axis limits: \pgfplotscoordmath{#1}{datascaletrafo}{\pgfplots@loc@TMPa}% \expandafter\let\csname pgfplots@#1min\endcsname=\pgfmathresult \pgfplotscoordmath{#1}{datascaletrafo}{\pgfplots@loc@TMPb}% \expandafter\let\csname pgfplots@#1max\endcsname=\pgfmathresult \fi }{}% }% % Inspects the limit enlargement factors and reinitializes the data % scale transformations. % % The purpose of this method is to avoid "dimension too large" if the % factors exceed certain limits. % % INPUT: % \pgfplots@target@limitrescale@x and its variants for y and z % \pgfplots@target@unit@scale@inv@x and its variants for y and z % % OUTPUT: % \pgfplots@target@datascaletrafo@x@exponent and its variants for y and z % -> contains NEW datascaletrafo exponents % \pgfplots@target@datascaletrafo@x@exponent@old and its variants for y and z % -> contains OLD datascaletrafo exponents % \pgfplots@target@unit@scale@inv@x and its variants for y and z % -> contains (modified) unit vector scales \def\pgfplots@scaling@adjust@datascaling{% \pgfplots@scaling@adjust@datascaling@for x% \pgfplots@scaling@adjust@datascaling@for y% \pgfplots@scaling@adjust@datascaling@for z% } \def\pgfplots@scaling@adjust@datascaling@for#1{% \pgfplots@if{pgfplots@apply@datatrafo@#1}{% \pgfplotscoordmath{#1}{datascaletrafo get params}% \def\pgfplots@loc@TMPa##1##2{% \expandafter\def\csname pgfplots@target@datascaletrafo@#1@exponent\endcsname{##1}% \expandafter\def\csname pgfplots@target@datascaletrafo@#1@exponent@old\endcsname{##1}% }% \expandafter\pgfplots@loc@TMPa\pgfmathresult \pgf@xa=\csname pgfplots@target@limitrescale@#1\endcsname pt \ifdim\pgf@xa>5pt % % We want to enlarge axis limits considerably! % \pgfplots@scaling@adjust@datascaling@for@get@compensation{\pgf@xa}% % % Ok, make sure that we do not get "dimension too large" % by adjusting the data scale trafo. % % Note that the data scale trafo has (only) been applied % to axis limits, so we have to reapply it before these % changes can take effect: \pgf@xa=\csname pgfplots@target@unit@scale@inv@#1\endcsname pt \divide\pgf@xa by\pgfplotsretval\relax % \expandafter\edef\csname pgfplots@target@unit@scale@inv@#1\endcsname{\pgf@sys@tonumber\pgf@xa}% % \c@pgf@countd=\csname pgfplots@target@datascaletrafo@#1@exponent\endcsname\relax \advance\c@pgf@countd by-\pgfplotsretvalb\relax % \expandafter\edef\csname pgfplots@target@datascaletrafo@#1@exponent\endcsname{\the\c@pgf@countd}% \fi }{% \expandafter\def\csname pgfplots@target@datascaletrafo@#1@exponent\endcsname{0}% \expandafter\def\csname pgfplots@target@datascaletrafo@#1@exponent@old\endcsname{0}% }% } % Returns % \pgfplotsretval -> the absolute scaling % \pgfplotsretvalb -> the log10 of the scaling \def\pgfplots@scaling@adjust@datascaling@for@get@compensation#1{ \ifdim#1<100pt % \def\pgfplotsretval{10}% \def\pgfplotsretvalb{1}% \else \ifdim#1<1000pt % \def\pgfplotsretval{100}% \def\pgfplotsretvalb{2}% \else \ifdim#1<10000pt % \def\pgfplotsretval{1000}% \def\pgfplotsretvalb{3}% \else % too much for this approach anyway... and probably no % use-case at all. \def\pgfplotsretval{1000}% \def\pgfplotsretvalb{3}% \fi \fi \fi }% % Computes the initial scale from a plot box of unit size to the % desired with and height. % % #1 the desired width % #2 the desired height % #3 [output] a macro which will contain the horizontal (x) scale % #4 [output] a macro which will contain the vertical (y) scale % #5 [input/output] a macro which, on input, contains the x axis limit compensation scale % which is required to select a single unit vector scale without % reducing the plots dimension (without actually respecting the % final dimension). On output, the input has been multiplied by % some additional x limit componensation scale (selected by scale % uniformly strategy). % #6 [input/output] a macro which will contain a y axis limit % compensation scale; it works in the same way as #5 % #7 [input/output] a macro which will contain a z axis limit % compensation scale; it works in the same way as #5 \def\pgfplots@get@scale@horiz@and@vert#1#2#3#4#5#6#7{% \begingroup \edef\pgfplots@target@limitrescale@x{#5}% \edef\pgfplots@target@limitrescale@y{#6}% \edef\pgfplots@target@limitrescale@z{#7}% \pgfplots@get@dimension@of@BB \pgf@xa=\pgfplotsretval\relax \pgf@xb=\pgfplotsretvalb\relax \pgf@ya=#1\relax \pgf@yb=#2\relax \edef\w{\pgf@sys@tonumber\pgf@xa}% \edef\h{\pgf@sys@tonumber\pgf@xb}% \edef\W{\pgf@sys@tonumber\pgf@ya}% \edef\H{\pgf@sys@tonumber\pgf@yb}% %\message{PGFPLOTS: the current unit vectors result in a UNIT BB of (\the\pgf@xa,\the\pgf@xb). Scaling it to (\the\pgf@ya,\the\pgf@yb)...^^J}% \ifcase\pgfplots@scale@mode@choice % scale mode=auto does not happen here \or % scale mode=none does not happen here \or % scale mode=stretch to fill % % This is very simple: % % Compute individual scaling factors for X and Y % such that the UNIT-BB will have size #1,#2. Keep limits. \pgfmathdivide@{\W}{\w}% \let\scalex=\pgfmathresult % \pgfmathdivide@{\H}{\h}% \let\scaley=\pgfmathresult % % no changes to the axis limits - we only rescale units. \def\pgfplots@target@limitrescale@x@{1}% \def\pgfplots@target@limitrescale@y@{1}% \def\pgfplots@target@limitrescale@z@{1}% \pgfplots@BB@update@cumulative@limit@compensations \or % scale mode=scale uniformly % compute ONE common scale for both, X and Y - and satisfy % width/height constraints by adjusting the axis limits. % % The idea is as follows: % we WANT to have width W and height H. % The constraint is that each unit vector must get the same % scale -- but the axis limits can receive individual % compensation scales. But it should "look reasonable well". % % currently, we have % w = r_x e_xx + r_y e_yx + rz e_zx (with e_zx = 0 typically) % h = r_x e_xy + r_y e_yy + rz e_zy % % where r_x, r_y, r_z are the maximal range of the data in % x,y,z respectively. Depending on the context of this method, % they are either 1 (relative coords) or % (xmax-xmin) (absolute coords). % % Now, search for a set of real numbers % Rx, Ry, Rz, s % such that % W = (Rx r_x) (s e_xx) + (Ry r_y) (s e_yx) + (Rz r_z) (s e_zx) % H = (Rx r_x) (s e_xy) + (Ry r_y) (s e_yy) + (Rz r_z) (s e_zy) % % clearly, the solution is not unique. % ONE choice is to employ the fact that e_zx = 0 (or, for 2d % plots, e_zx=0, e_zy=0 and e_yx=0): % % in that case, we can compute s such that the equation for W % is satisfied and compensate only the limit r_z, i.e. to % choose % s := W / w, (scale to satisfy width constraint) % Rx := Ry := 1 (keep limits in X and Y) % Rz = ( H - s (w - r_z e_zy) ) / (s r_z e_zy) (adjust z limit to satisfy height constraint) % % This approach works well if W < H . If W > H, it will look % bad: Rz will be less than 1, causing the limit to become % smaller. This, in turn, will clip away parts of the image. % % % % Another solution is to make it the other way: to keep the % limit r_z, but to reduce the size and enlarge the other % limits to satisfy the size constraints. This solution is % considerably more involved; it requires to solve a nonlinear % set of equations. % % Formally, this second solution uses % Rz := 1 (no limit componensation scale for z -- keep z limit) % R:= Rx := Ry (same limit componensation scale for both X and Y) % R and s still need to be determined from the two equations for W % and H. % % Substituting the given choices into the equations for W and H, we find % % R = W / (s w) % % s = H * (R * (h-r_z e_zy) + r_z e_zy)^-1 % % Here, we employed the definition of 'h', see above. The % equations are non-linear. % % ATTENTION: we assume that the datascaletrafo set params % method has been called with THE SAME SCALE IN EACH % DIRECTION. \if0\pgfplots@scaleuniformly@choice % scale uniformly strategy=auto \pgfplots@get@scale@horiz@and@vert@scaleuniformly@of@optimal@strategy \else \pgfplots@get@scale@horiz@and@vert@scaleuniformly \pgfplots@BB@update@cumulative@limit@compensations \fi \fi % \xdef\pgfplots@glob@TMPa{% \noexpand\def\noexpand#3{\scalex}% \noexpand\def\noexpand#4{\scaley}% \noexpand\def\noexpand#5{\pgfplots@target@limitrescale@x}% \noexpand\def\noexpand#6{\pgfplots@target@limitrescale@y}% \noexpand\def\noexpand#7{\pgfplots@target@limitrescale@z}% }% \endgroup \pgfplots@glob@TMPa }% % This is the implementation for 'scale uniformly strategy=auto'. % % It works by finding the strategy which involves the minimal scaling % overhead. % % To this end, it computes the result for each 'scale uniformly % strategy', and computes a cost function. The one with optimal cost % function wins, and its results are returned. % % The cost function is the overal scaling which is applied to AXIS % LIMITS. It works as follows: % 1. if a choice requires to REDUCE the axis limits in order to % fulfill all constraints, it is neglected (using maximal cost 16000). % Reducing axis limits may clip away information. % % 2. if a choice requires to ENLARGE some axis limits, its cost is the % sum of the individual scaling factors (even if they are are one - % who cares). % % Note that this method *is* relevant and the optimization appears to % be necessary. % Examples are % unittest_scalemode_2d_standard_1.tex % and perhaps % unittest_scalemode_2d_standard_0.tex % and more involved 3d examples are also available. % % My first guess was that it is sufficient to decide the optimal % strategy in advance by comparing the target width and the target % height - but that proved to be insufficient: it leads to correct % results, but wastes too much space (i.e. enlarges limits too much). % % ATTENTION: the cost function INCLUDES RESULTS OF % \pgfplots@BB@for@plotbox@get@unit@scales@for@limits and its % corrector % \pgfplots@BB@for@plotbox@get@unit@scales@compensated@axis@limits. % % More precisely, it relies on already computes limit compensation % factors which do not depend on the target width/target height: both % \pgfplots@BB@for@plotbox@get@unit@scales@compensated@axis@limits and % this implementation of 'scale uniformly strategy' can be used to compute % the cost of a strategy. % \def\pgfplots@get@scale@horiz@and@vert@scaleuniformly@of@optimal@strategy{% \begingroup \def\mathclass{default}% \pgfplotscoordmath{\mathclass}{max limit}% \let\pgfplots@cost@for@choice@superhigh=\pgfmathresult% % % private helpers to compute the cost. \def\pgfplots@scalestrategy@compute@cost{% \begingroup % ATTENTION: this call changes % '\pgfplots@target@limitrescale@x' and its variants. % Restore its value after the iteration: \pgfplots@BB@update@cumulative@limit@compensations \pgfplotscoordmath{\mathclass}{one}% \let\ONE=\pgfmathresult \pgfplotscoordmath{\mathclass}{parsenumber}{\pgfplots@target@limitrescale@x}% \let\X=\pgfmathresult \pgfplotscoordmath{\mathclass}{parsenumber}{\pgfplots@target@limitrescale@y}% \let\Y=\pgfmathresult \ifpgfplots@threedim \pgfplotscoordmath{\mathclass}{parsenumber}{\pgfplots@target@limitrescale@z}% \let\Z=\pgfmathresult \else \let\Z=\pgfplots@target@limitrescale@z \fi % % If one of the resulting limit compensation scales is % less than 1, we can immediately skip it - we do not want % to risk to clip away image content. \pgfplotscoordmath{\mathclass}{if less than}{\X}{\ONE}{% \let\pgfplots@cost@for@choice=\pgfplots@cost@for@choice@superhigh }{% \pgfplotscoordmath{\mathclass}{if less than}{\Y}{\ONE}{% \let\pgfplots@cost@for@choice=\pgfplots@cost@for@choice@superhigh }{% \ifpgfplots@threedim \pgfplotscoordmath{\mathclass}{if less than}{\Z}{\ONE}{% \let\pgfplots@cost@for@choice=\pgfplots@cost@for@choice@superhigh }{% % ah - 3 limit scales >= 1. Good, assign cost: \pgfplots@scalestrategy@compute@cost@ }% \else % ah - all limit scales >=1. Good, assign cost: \pgfplots@scalestrategy@compute@cost@ \fi }% }% %\message{scale uniformly strategy=auto: '\pgfplots@tostring@scaleuniformlystrategy{\pgfplots@scaleuniformly@choice}' has cost \pgfplots@cost@for@choice\space(limit rescaling factors x=\X, y=\Y, z=\Z)^^J}% \xdef\pgfplots@glob@TMPa{% \noexpand\def\noexpand\pgfplots@scaleuniformly@choice{\pgfplots@scaleuniformly@choice}% \noexpand\def\noexpand\scalex{\scalex}% \noexpand\def\noexpand\scaley{\scaley}% \noexpand\def\noexpand\pgfplots@target@limitrescale@x{\pgfplots@target@limitrescale@x}% \noexpand\def\noexpand\pgfplots@target@limitrescale@y{\pgfplots@target@limitrescale@y}% \noexpand\def\noexpand\pgfplots@target@limitrescale@z{\pgfplots@target@limitrescale@z}% }% \pgfmath@smuggleone\pgfplots@cost@for@choice % keep in mind that this scope IS NECESSARY: we have % changed the target quantities % \pgfplots@target@limitrescale@x and its variants! \endgroup \let\pgfplots@scalestrategy@values=\pgfplots@glob@TMPa }% \def\pgfplots@scalestrategy@compute@cost@{% \pgfplotscoordmath{\mathclass}{op}{add}{{\X}{\Y}}% \ifpgfplots@threedim \pgfplotscoordmath{\mathclass}{op}{add}{{\pgfmathresult}{\Z}}% \fi \let\pgfplots@cost@for@choice=\pgfmathresult }% % % compute initial cost: \def\pgfplots@scaleuniformly@choice{3}% change horizontal limits \pgfplots@get@scale@horiz@and@vert@scaleuniformly \pgfplots@scalestrategy@compute@cost % % init minimum: \let\pgfplots@cost@for@choice@arg=\pgfplots@scalestrategy@values \let\pgfplots@cost@for@choice@sofar=\pgfplots@cost@for@choice% % % compute cost of next strategy: \def\pgfplots@scaleuniformly@choice{2}% change vertical limits \pgfplots@get@scale@horiz@and@vert@scaleuniformly \pgfplots@scalestrategy@compute@cost % % update minimum: \pgfplotscoordmath{\mathclass}{if less than}{\pgfplots@cost@for@choice}{\pgfplots@cost@for@choice@sofar}{% \let\pgfplots@cost@for@choice@arg=\pgfplots@scalestrategy@values \let\pgfplots@cost@for@choice@sofar=\pgfplots@cost@for@choice% }{% }% % \ifx\pgfplots@cost@for@choice@sofar\pgfplots@cost@for@choice@superhigh % the algorithm discarded every available strategy. \def\pgfplots@scaleuniformly@choice{1}% fall back to 'units only' \pgfplots@get@scale@horiz@and@vert@scaleuniformly \pgfplots@scalestrategy@compute@cost \let\pgfplots@cost@for@choice@arg=\pgfplots@scalestrategy@values \let\pgfplots@cost@for@choice@sofar=\pgfplots@cost@for@choice% \fi % % \global\let\pgfplots@glob@TMPa=\pgfplots@cost@for@choice@arg \endgroup \pgfplots@glob@TMPa %\message{scale uniformly strategy=auto: choosing '\pgfplots@tostring@scaleuniformlystrategy{\pgfplots@scaleuniformly@choice}'^^J}% } \def\pgfplots@tostring@scaleuniformlystrategy#1{% % scale uniformly strategy: \ifcase#1\relax auto \or units only \or change vertical limits \or change horizontal limits \fi } % Does the work for 'scale mode=scale uniformly' inside of % \pgfplots@get@scale@horiz@and@vert. % % It returns its result into \pgfplots@target@limitrescale@x@ (i.e. % with an extra '@') \def\pgfplots@get@scale@horiz@and@vert@scaleuniformly{% \ifcase\pgfplots@scaleuniformly@choice\relax % scale uniformly strategy=auto does not happen here. \or % scale uniformly strategy=units only \pgfplots@scaleuniformly@onlyunits \or % scale uniformly strategy=change vertical limits % % first, scale to the width ... \pgfplots@scaleuniformly@onlyunits@{\w}{\W}% % ... and change (only) vertical limits to get the "correct" % height: \ifdim\pgf@zy=0pt \ifdim\pgf@yx=0pt \pgfplots@prepare@vertical@rescaling@for@scale@uniformly@in@dir{y}\returninto\pgfplots@target@limitrescale@y@ \else \pgfplots@scale@uniformly@fallback \fi \else \ifdim\pgf@zx=0pt \pgfplots@prepare@vertical@rescaling@for@scale@uniformly@in@dir{z}\returninto\pgfplots@target@limitrescale@z@ \else \pgfplots@scale@uniformly@fallback \fi \fi \or % scale uniformly strategy=change horizontal limits \ifdim\pgf@zy=0pt \ifdim\pgf@yx=0pt \ifdim\pgf@xy=0pt % special 2d routine with explicit solution \pgfplots@scaleuniformly@change@horizontal@limits@twodim {\scalex} {\pgfplots@target@limitrescale@x@} {\pgfplots@target@limitrescale@y@} {\pgfplots@target@limitrescale@z@}% \else \pgfplots@scale@uniformly@fallback \fi \else \pgfplots@scale@uniformly@fallback \fi \else \ifdim\pgf@zx=0pt \pgfplots@scaleuniformly@change@horizontal@limits {\scalex} {\pgfplots@target@limitrescale@x@} {\pgfplots@target@limitrescale@y@} {\pgfplots@target@limitrescale@z@}% \else \pgfplots@scale@uniformly@fallback \fi \fi \let\scaley=\scalex \fi } \def\pgfplots@scaleuniformly@onlyunits{% % scale to the smaller target dimension: \ifdim\W pt<\H pt % \pgfplots@scaleuniformly@onlyunits@{\w}{\W}% \else \pgfplots@scaleuniformly@onlyunits@{\h}{\H}% \fi }% % #1 : the actual dimension % #2 : the target dimension \def\pgfplots@scaleuniformly@onlyunits@#1#2{% \def\pgfplots@target@limitrescale@x@{1}% \def\pgfplots@target@limitrescale@y@{1}% \def\pgfplots@target@limitrescale@z@{1}% \pgfmathdivide@{#2}{#1}% \let\scalex=\pgfmathresult \let\scaley=\scalex % we *need* the same unit scale. }% % Computes 'scale uniformly strategy=change horizontal limits'. % This is a complicated solution, see the documentation in the % implementation for % 'scale mode=scale uniformly' % % #1 [output] a macro which will contain the (uniform) scale for the % unit vectors % #2 [output] a macro which will contain a x axis limit compensation scale % #3 [output] a macro which will contain a x axis limit compensation scale % #4 [output] a macro which will contain a x axis limit compensation scale \def\pgfplots@scaleuniformly@change@horizontal@limits#1#2#3#4{% \begingroup % \pgfplots@BB@for@plotbox@getunitheight{\pgf@xc}{z}% % % compute the rest in floating point - intermediate results may % become too huge for TeX. \pgfplotscoordmath{default}{parsenumber}{\expandafter\pgf@sys@tonumber\csname pgf@xc\endcsname}% \let\M=\pgfmathresult % \pgfplotscoordmath{default}{parsenumber}{\w}% \let\w=\pgfmathresult \pgfplotscoordmath{default}{parsenumber}{\W}% \let\W=\pgfmathresult \pgfplotscoordmath{default}{parsenumber}{\h}% \let\h=\pgfmathresult \pgfplotscoordmath{default}{parsenumber}{\H}% \let\H=\pgfmathresult \pgfplotscoordmath{default}{op}{divide}{{\W}{\w}}% \let\Wwinv=\pgfmathresult \pgfplotscoordmath{default}{op}{subtract}{{\h}{\M}}% \let\hminusM=\pgfmathresult % \pgfplotscoordmath{default}{one}% \let\S=\pgfmathresult% \let\R=\pgfmathresult% \let\Rx=\pgfmathresult \def\Rz{1}% % \def\pgfplots@hold@S@get@R{% \pgfplotscoordmath{default}{op}{divide}{{\Wwinv}{\S}}% \let\R=\pgfmathresult %\message{updated R = \R\space ( S = \S ) ^^J}% }% \def\pgfplots@hold@R@get@S{% \pgfplotscoordmath{default}{op}{multiply}{{\R}{\hminusM}}% \pgfplotscoordmath{default}{op}{add}{{\pgfmathresult}{\M}}% \pgfplotscoordmath{default}{op}{divide}{{\H}{\pgfmathresult}}% \let\S=\pgfmathresult %\message{updated S = \S\space ( R = \R ) ^^J}% }% % % This is the (most stupid) nonlinear method which is at hand: % fix point iteration. % choose R arbitrarily (R=1 seems adequate), solve for s. % Then, fix s and solve for R. Then, fix R and % solve for s until convergence. \c@pgf@countc=0 \pgfplotsloop{% \ifnum\c@pgf@countc<\pgfkeysvalueof{/pgfplots/scale uniformly strategy iter} % \pgfplotsloopcontinuetrue \else \pgfplotsloopcontinuefalse \fi }{% \pgfplots@hold@R@get@S \pgfplots@hold@S@get@R \advance\c@pgf@countc by1 % }% % \pgfplotscoordmath{default}{tofixed}{\R}\let\R=\pgfmathresult \pgfplotscoordmath{default}{tofixed}{\S}\let\S=\pgfmathresult \xdef\pgfplots@glob@TMPa{% \noexpand\def\noexpand#1{\S}% \noexpand\def\noexpand#2{\R}% \noexpand\def\noexpand#3{\R}% \noexpand\def\noexpand#4{\Rz}% }% \endgroup % \pgfplots@glob@TMPa }% % Computes 'scale uniformly strategy=change horizontal limits'. % % This is a simplified closed solution assuming that e_xy=0 and e_yx = 0 % % #1 [output] a macro which will contain the (uniform) scale for the % unit vectors % #2 [output] a macro which will contain a x axis limit compensation scale % #3 [output] a macro which will contain a x axis limit compensation scale % #4 [output] a macro which will contain a x axis limit compensation scale \def\pgfplots@scaleuniformly@change@horizontal@limits@twodim#1#2#3#4{% \begingroup % Assuming that we have a standard 2d axis, i.e. % e_zx = e_zy = 0, e_xy = 0, and e_yx =0, % we can immediately compute a solution. % % In this case, we have the actual width % w = r_x e_xx + r_y e_yx + rz e_zx % = r_x e_xx % and actual height % h = r_x e_xy + r_y e_yy + rz e_zy % = r_y e_yy % and, consequently, desired width % W = (Rx r_x) (s e_xx) + (Ry r_y) (s e_yx) + (Rz r_z) (s e_zx) % = (Rx r_x) (s e_xx) % and desired height % H = (Rx r_x) (s e_xy) + (Ry r_y) (s e_yy) + (Rz r_z) (s e_zy) % = (Ry r_y) (s e_yy). % since this strategy changes horizontal limits (only), we have % Ry := 1. % We find % s : = H/h % and % Rx : = W/w /s . % \pgfplotscoordmath{default}{parsenumber}{\w}% \let\w=\pgfmathresult \pgfplotscoordmath{default}{parsenumber}{\W}% \let\W=\pgfmathresult \pgfplotscoordmath{default}{parsenumber}{\h}% \let\h=\pgfmathresult \pgfplotscoordmath{default}{parsenumber}{\H}% \let\H=\pgfmathresult \pgfplotscoordmath{default}{op}{divide}{{\H}{\h}}% \let\S=\pgfmathresult \pgfplotscoordmath{default}{op}{divide}{{\W}{\w}}% \pgfplotscoordmath{default}{op}{divide}{{\pgfmathresult}{\S}}% \let\Rx=\pgfmathresult \def\Ry{1}% \def\Rz{1}% % \pgfplotscoordmath{default}{tofixed}{\Rx}\let\Rx=\pgfmathresult \pgfplotscoordmath{default}{tofixed}{\S}\let\S=\pgfmathresult \xdef\pgfplots@glob@TMPa{% \noexpand\def\noexpand#1{\S}% \noexpand\def\noexpand#2{\Rx}% \noexpand\def\noexpand#3{\Ry}% \noexpand\def\noexpand#4{\Rz}% }% \endgroup % \pgfplots@glob@TMPa }% \def\pgfplots@BB@update@cumulative@limit@compensations{% %\message{ -> additional limit componensation scales x=\pgfplots@target@limitrescale@x@, y=\pgfplots@target@limitrescale@y@, z=\pgfplots@target@limitrescale@z@^^J}% % add limit compensation to what we have from earlier % operations: \pgfplotscoordmath{pgfbasic}{op}{multiply}{{\pgfplots@target@limitrescale@x@}{\pgfplots@target@limitrescale@x}}% \let\pgfplots@target@limitrescale@x=\pgfmathresult \pgfplotscoordmath{pgfbasic}{op}{multiply}{{\pgfplots@target@limitrescale@y@}{\pgfplots@target@limitrescale@y}}% \let\pgfplots@target@limitrescale@y=\pgfmathresult \pgfplotscoordmath{pgfbasic}{op}{multiply}{{\pgfplots@target@limitrescale@z@}{\pgfplots@target@limitrescale@z}}% \let\pgfplots@target@limitrescale@z=\pgfmathresult }% \def\pgfplots@scale@uniformly@fallback{% \ifpgfplots@scaleuniformly@warning \pgfplotswarning{scale uniformly unsupported}\pgfeov% \fi \pgfplots@scaleuniformly@onlyunits }% % This is part of the implementation of 'scale mode=scale uniformly'. % % Its purpose it to set up the initial scaling such that % 1. each unit vector gets the same scale % 2. the axis limits are resized (enlarged) to keep the plot box ratio % (as far as possible) % % It repairs the outcome of % \pgfplots@BB@for@plotbox@get@unit@scales@for@limits . % % The assumption is that on input #1, #2, and #3 are the factors which % would be used by stretch-to-fill in order to squeze the axis limits % into the plot box defined by e_x, e_y, and e_z (the unit vectors). % % On output, #1, #2, and #3 will be modified such that *each has the % same value*. The value will be chosen with care. More precisely, it % is the *minimum* of {#1,#2,#3}. % % Clearly, 'scale mode=scale uniformly' has less freedom than % strech-to-fill. In order to keep the plot box ratio intact (as far % as possible), the axis limits will be rescaled to componsate for the % ignored scaling factors. More precisely, if direction i is not the % extremal value (as discussed in the last paragraph), the axis limits % will be rescaled by #i/extremum . % % % % #1: on input, it contains the x unit scale which would be taken without the % compensation. On output, it contains the x unit scale which *will* be % used. % #2: same as #1, but for y % #3: same as #1, but for z % #4: [output] a scale for use as argument of \pgfplots@apply@unit@vector@rescale@keep@size{x}{} % #5: [output] a scale for use as argument of \pgfplots@apply@unit@vector@rescale@keep@size{y}{} % #6: [output] a scale for use as argument of \pgfplots@apply@unit@vector@rescale@keep@size{z}{} % % The output arguments need to be applied before they take effect. \def\pgfplots@BB@for@plotbox@get@unit@scales@compensated@axis@limits#1#2#3#4#5#6{% \begingroup % ATTENTION : this code ASSUMES that the datascaling trafo is % initialized with THE SAME SCALE IN EACH DIRECTION. % The data scaling also leads to (potentially non-uniform) scaling per component. % % Note that we could handle the datascaling here -- but we would % leave the supported number range easily. That's why that part of % the 'scale mode=scale uniformly' implementation has been moved % to \pgfplots@set@optimal@datatrafos@allaxes % % This here handles the limits only. \edef\pgfplots@scale@unitx{#1}% \edef\pgfplots@scale@unity{#2}% \edef\pgfplots@scale@unitz{#3}% % % compute extreme + arg extreme of these scales: \def\pgfplots@extreme@scale{-16300}% \def\pgfplots@extreme@scale@arg{NONE}% % \if0\b@pgfplots@unitvec@is@zero@x \ifdim\pgfplots@extreme@scale pt<\pgfplots@scale@unitx pt \let\pgfplots@extreme@scale=\pgfplots@scale@unitx \def\pgfplots@extreme@scale@arg{x}% \fi \fi \if0\b@pgfplots@unitvec@is@zero@y \ifdim\pgfplots@extreme@scale pt<\pgfplots@scale@unity pt \let\pgfplots@extreme@scale=\pgfplots@scale@unity \def\pgfplots@extreme@scale@arg{y}% \fi \fi \if0\b@pgfplots@unitvec@is@zero@z \ifdim\pgfplots@extreme@scale pt<\pgfplots@scale@unitz pt \let\pgfplots@extreme@scale=\pgfplots@scale@unitz \def\pgfplots@extreme@scale@arg{z}% \fi \fi % % Now, adjust axis limits to compensate for the effect: we still % want to have a plot box which is as close as possible to the % target plot box. \def\pgfplots@loc@TMPa##1##2{% \if0\csname b@pgfplots@unitvec@is@zero@##1\endcsname \if1\pgfplots@scaleuniformly@choice % FIXME : this appears to be too much. Disable this!? % ok, nothing to do for this direction. \pgfplotscoordmath{pgfbasic}{one}% \let##2=\pgfmathresult \else \if\pgfplots@extreme@scale@arg ##1% % ok, nothing to do for this direction. \pgfplotscoordmath{pgfbasic}{one}% \let##2=\pgfmathresult \else \pgfplotscoordmath{pgfbasic}{op}{divide}{{\pgfplots@extreme@scale}{\csname pgfplots@scale@unit##1\endcsname}}% % do not call apply@unit@rescale immediately because the % unit vectors may not be in their final state. Postpone until % they are final. \edef##2{\pgfmathresult}% \fi \fi \else \def##2{1}% \fi }% \pgfplots@loc@TMPa{x}{#4}% \pgfplots@loc@TMPa{y}{#5}% \pgfplots@loc@TMPa{z}{#6}% % \toks0=\expandafter{#4}% \toks1=\expandafter{#5}% \toks2=\expandafter{#6}% \xdef\pgfplots@glob@TMPa{% % same scale in each dir: \def\noexpand#1{\pgfplots@extreme@scale}% \def\noexpand#2{\pgfplots@extreme@scale}% \def\noexpand#3{\pgfplots@extreme@scale}% \def\noexpand#4{\the\toks0}% \def\noexpand#5{\the\toks1}% \def\noexpand#6{\the\toks2}% }% \endgroup \pgfplots@glob@TMPa } % #1 : a dimen register % #2 : x, y, or z \def\pgfplots@BB@for@plotbox@getunitheight#1#2{% #1=\csname pgfplots@plotbox@#2max\endcsname\csname pgf@#2y\endcsname \advance#1 by -\csname pgfplots@plotbox@#2min\endcsname\csname pgf@#2y\endcsname \ifdim#1<0pt % % we want to return a height. It is also bigger than 0. % the difference above may be negative if the unit points % downward (special combinations of view/h and view/v) #1=-#1\relax \fi }% % Modifies the AXIS LIMITS to ensure that a suitable width/height is % achieved. % % This does NOT introduce a further scale to the unit vectors. % % #1: a direction (x,y, or z) % #2: a macro name. It will be assigned globally. It will contain % EXECUTABLE instructions which will modify the axis limits to fit the % scaling. % % PRECONDITION: % - \pgfplots@glob@TMPa contains the already computed % scaling factor for 'scale uniformly' % - \pgf@xb is the actual height and \pgf@yb is the desired height % (set as in the scaling routine) % % POSTCONDITION: % #2 will contain the argument for \pgfplots@apply@unit@vector@rescale@keep@size{#1}{} \def\pgfplots@prepare@vertical@rescaling@for@scale@uniformly@in@dir#1\returninto#2{% % The strategy is as follows: % 1. I want to fit the axis into width #1 (\pgf@ya) and % height #1 (\pgf@yb). % 2. I want to MAINTAIN the unit vector ratio. % 3. I want to MAINTAIN the unit vector directions. % % I already know the scaling factor to fit the width (it % is stored in \scalex = \scaley). % Let's call it "s". % % Consequently, a uniform scaling by "s" leads to the image % height % h = s* (r_x * e_xy + r_y * e_yy + r_z * e_zy) % where r_i = (imax - imin). This here is essentially the % same as the bounding box computation above (at least for % standart orthographic 3D axes). % % What I want now is to enlarge the limits such that I % have BOTH, width #1 AND height #2, without obscuring the % unit vector ratio. Recall that width #1 is already % given. % % This strategy achieves this goal by % modifying axis limits for an axis whose unit vector is % parallel to the canvas y axis, i.e. e_i = (0,*). % % That means I have to introduce a SECOND scale s_z which % applies only to the Z unit vector (since e_z = (0,*) ). % If H = #2 is the desired height, I find the target % equation for s_z, % % H = s* r_x e_xy + s * r_y e_yy + s_z * s * r_z * e_zy % => % s_z = ( H- s*r_x e_xy - s*r_y e_yy) / ( s * r_z * e_zy). % % Remember that % s = \scalex % H = \H % h = r_x * e_xy + r_y * e_yy + r_z * e_zy = \h % => % s_z = ( H- s*( h - r_z * e_zy) ) / ( s * r_z * e_zy). % \begingroup \pgfplots@BB@for@plotbox@getunitheight{\pgf@xc}{#1}% % % compute the rest in floating point - intermediate results may % become too huge for TeX. \pgfplotscoordmath{default}{parsenumber}{\expandafter\pgf@sys@tonumber\csname pgf@xc\endcsname}% \let\pgfplots@diff=\pgfmathresult % \pgfplotscoordmath{default}{parsenumber}{\scalex}% \let\pgfplots@s=\pgfmathresult % % this is a precondition of this method: \pgfplotscoordmath{default}{parsenumber}{\h}% \let\h=\pgfmathresult \pgfplotscoordmath{default}{parsenumber}{\H}% \let\H=\pgfmathresult % % compute counter := H - s * (h - (max-min)) \pgfplotscoordmath{default}{op}{subtract}{{\h}{\pgfplots@diff}}% \pgfplotscoordmath{default}{op}{multiply}{{\pgfplots@s}{\pgfmathresult}}% \pgfplotscoordmath{default}{op}{subtract}{{\H}{\pgfmathresult}}% \let\pgfplots@counter=\pgfmathresult % % computer denom := s * (max-min) \pgfplotscoordmath{default}{op}{multiply}{{\pgfplots@s}{\pgfplots@diff}}% \let\pgfplots@denom=\pgfmathresult % \pgfplotscoordmath{default}{op}{divide}{{\pgfplots@counter}{\pgfplots@denom}}% \pgfplotscoordmath{default}{tofixed}{\pgfmathresult}% % % Now, s_z = \pgfmathresult . % % Now, adjust the z limits. % Note that \pgfplots@apply@unit@vector@rescale@keep@size % has a slightly different context; it assumes that the % unit vector has been rescaled, not the axis limits. % Consequently, the inverse of the scaling factor enters. % Since \pgfplots@apply@unit@vector@rescale@keep@size % expects the inverse of the scale, we can provide % \pgfmathresult: \pgfmath@smuggleone\pgfmathresult \endgroup \let#2=\pgfmathresult } \def\pgfplots@computeunitvectorlengths{% \pgfplotsutil@edef@invoke\pgfmathveclen@{% {\pgf@sys@tonumber\pgf@xx}% {\pgf@sys@tonumber\pgf@xy}% }% \let\pgfplots@x@veclength=\pgfmathresult \pgfplotsmath@ifzero{\pgfplots@x@veclength}{% \def\pgfmathresult{infty}% % this case will be caught in \pgfplots@initsizes }{% \expandafter\pgfmath@basic@reciprocal@\expandafter{\pgfmathresult}% }% \let\pgfplots@x@inverseveclength=\pgfmathresult % \pgfplotsutil@edef@invoke\pgfmathveclen@{% {\pgf@sys@tonumber\pgf@yx}% {\pgf@sys@tonumber\pgf@yy}% }% \let\pgfplots@y@veclength=\pgfmathresult \pgfplotsmath@ifzero{\pgfplots@y@veclength}{% \def\pgfmathresult{infty}% % this case will be caught in \pgfplots@initsizes }{% \expandafter\pgfmath@basic@reciprocal@\expandafter{\pgfmathresult}% }% \let\pgfplots@y@inverseveclength=\pgfmathresult % \ifpgfplots@threedim \pgfplotsutil@edef@invoke\pgfmathveclen@{% {\pgf@sys@tonumber\pgf@zx}% {\pgf@sys@tonumber\pgf@zy}% }% \let\pgfplots@z@veclength=\pgfmathresult \pgfplotsmath@ifzero{\pgfplots@z@veclength}{% \def\pgfmathresult{infty}% % this case will be caught in \pgfplots@initsizes }{% \expandafter\pgfmath@basic@reciprocal@\expandafter{\pgfmathresult}% }% \let\pgfplots@z@inverseveclength=\pgfmathresult \else \def\pgfplots@z@veclength{0}% \def\pgfplots@z@inverseveclength{infty}% \fi }% % Defines \pgfplots@view@dir@threedim according to the actual % configuration of x,y,z (2d) unit vectors, assuming the associated % unit vectors form a right-handed-system. % % The algorithm works for standard three dimensional axes. It works as % follows: % % First, observe that we have a normal direction N if all its % multiples are mapped onto the same point in 2D canvas % coordinates. In other words: all 3D coordinates which are mapped % onto an arbitrary point in 2D canvas coordinates (take, for example, % the origin (0,0) ) are on a line in direction of N. % % We use this observation to compute the normal axis, i.e. we search % for all points which are mapped onto the 2D canvas coordinate (0,0): % N_x e_xx + N_y e_yx + N_z e_zx = 0 % N_x e_xy + N_y e_yy + N_z e_zy = 0. % All solutions make up a linear space of dimension 1 (up to special % cases). In the general case, we can chose an arbitrary N_z != 0 % and reduce the linear system to % N_x e_xx + N_y e_yx = - N_z e_zx % N_x e_xy + N_y e_yy = - N_z e_zy. % Choosing *any* N_z != 0, say, N_z=-1 (which corresponds to view % from above) will lead to a vector parallel to the normal direction. % But it might have the wrong sign. % % FIXME : this fails if one of e_x or e_y is zero. % % To find the correct sign for N, I have made several case % distinctions to identify the cases when we have to multiply with -1. % The key idea is to assume a right-handed-system of unit vectors; % this is the condition which allows to determine the sign. % % Furthermore, I assume that e_z points to the top, i.e. that e_zy >0. % Then, there are (mainly) four conditions on the signs of e_x and e_y % which indicate that we are viewing from below and should switch the % sign of N (keep in mind that our initial choice was N_z =-1, see above). % % The conditions can be identified by drawing a 3D box and % identifying the corner which represents the lower left 3D limits. % % You can visualize these cases using %-------------------------------------------------- % \pgfplotsset{ % separate axis lines, % every outer x axis line/.append style= {-stealth}, % every outer y axis line/.append style= {-stealth}, % every outer z axis line/.append style= {-stealth}, % samples=2,shader=interp,title={view=\h,\v}, % domain=0:1, % enlargelimits=false, % view=\h\v,xlabel=x,ylabel=y, % extra description/.code={% % \node[draw,fill=white] at (axis cs:0,0,0) {}; % }, % } % % \def\v{30} % \foreach \h in {30,120,210,300} { % \message{VIEW={\h}{\v}^^J} % \begin{tikzpicture} % \begin{axis} % \addplot3[surf] {x}; % \end{axis} % \end{tikzpicture} % % } % % \def\v{-30} % \foreach \h in {30,120,210,300} { % \message{VIEW={\h}{\v}^^J} % \begin{tikzpicture} % \begin{axis} % \addplot3[surf] {x}; % \end{axis} % \end{tikzpicture} % % } %-------------------------------------------------- % The precise formulas can be found below in the source code. % % You can override this function by the /pgfplots/view dir key. \def\pgfplotsgetnormalforcurrentview{% \pgfkeysgetvalue{/pgfplots/view dir}\pgfplots@loc@TMPc \ifx\pgfplots@loc@TMPc\pgfutil@empty \begingroup % temporarily undo the effects of reversed axes -- we *really* % need a right-handed-coordinate system here: \if r\pgfkeysvalueof{/pgfplots/x dir/value}% \pgf@xx=-\pgf@xx \pgf@xy=-\pgf@xy \fi \if r\pgfkeysvalueof{/pgfplots/y dir/value}% \pgf@yx=-\pgf@yx \pgf@yy=-\pgf@yy \fi \if r\pgfkeysvalueof{/pgfplots/z dir/value}% \pgf@zx=-\pgf@zx \pgf@zy=-\pgf@zy \fi % FIRST: check for special cases. \let\pgfplots@view@dir@threedim=\pgfutil@empty% % Special case: % e_xx = e_xy = 0 % % i.e.: % % ^ % | |---| % z | | % |---| % y-> % % In this case, N must be the x axis. \ifdim\pgf@xx=0pt % \ifdim\pgf@xy=0pt % \def\pgfplots@view@dir@threedim{-1,0,0}% \fi \fi % Special case: % e_yx = e_yy = 0 % % i.e.: % % ^ % | |---| % z | | % |---| % x-> % % In this case, N must be the y axis. \ifdim\pgf@yx=0pt % \ifdim\pgf@yy=0pt % \def\pgfplots@view@dir@threedim{0,1,0}% \fi \fi % Special case: % e_xy = e_yy = 0 (i.e. one row) % % that is hard to draw, use view={30}{0} to see it. % % In this case, N_z must be 0 and we have a different system. \ifdim\pgf@xy=0pt % \ifdim\pgf@yy=0pt % \ifx\pgfplots@view@dir@threedim\pgfutil@empty % we have N_x e_xx + N_y e_yx = 0 % Note that e_xx != 0 and e_yx != 0 (otherwise one % of our other special cases above would have % caught the case) % -> we have N_x = -N_y e_yx / e_xx and N_y % arbitrary. only the sign needs to be fixed. \def\pgfplots@view@dir@threedim@z{0}% \def\pgfplots@view@dir@threedim@y{1}% fix it somehow. We correct the sign later. \edef\pgfplots@loc@TMPa{-(\pgfplots@view@dir@threedim@y) * \pgf@sys@tonumber\pgf@yx / (\pgf@sys@tonumber\pgf@xx)}% \pgfmathparse{\pgfplots@loc@TMPa}% \let\pgfplots@view@dir@threedim@x=\pgfmathresult % \def\pgfplots@scale{1}% % I identified these cases by comparing the % results with \pgfplots@scale{1} with those of % the view dir generated by % \pgfplotssetaxesfromazel (which has the correct quality of solution) \ifdim\pgf@zy>0pt % \ifdim\pgf@xx<0pt % \def\pgfplots@scale{-1}% \fi \else \ifdim\pgf@xx>0pt % \def\pgfplots@scale{-1}% \fi \fi \pgfmathmultiply@{\pgfplots@scale}{\pgfplots@view@dir@threedim@x}% \let\pgfplots@view@dir@threedim@x\pgfmathresult \pgfmathmultiply@{\pgfplots@scale}{\pgfplots@view@dir@threedim@y}% \let\pgfplots@view@dir@threedim@y\pgfmathresult \pgfmathmultiply@{\pgfplots@scale}{\pgfplots@view@dir@threedim@z}% \let\pgfplots@view@dir@threedim@z\pgfmathresult % \edef\pgfplots@view@dir@threedim{\pgfplots@view@dir@threedim@x,\pgfplots@view@dir@threedim@y,\pgfplots@view@dir@threedim@z}% \else % Ah - we already caught that special case above. \fi \fi \fi % % NOTE : the case e_xx = e_yx = 0 IS NO USE-CASE (would % require a rotated z axis which is forbidden currently) % \ifx\pgfplots@view@dir@threedim\pgfutil@empty \def\pgfplots@view@dir@threedim@z{-1}% hold it at some arbitrary value \pgf@xa=-\pgfplots@view@dir@threedim@z\pgf@zx \pgf@ya=-\pgfplots@view@dir@threedim@z\pgf@zy \edef\pgfplots@loc@TMPa{% {% {\pgf@sys@tonumber\pgf@xx}{\pgf@sys@tonumber\pgf@yx}% {\pgf@sys@tonumber\pgf@xy}{\pgf@sys@tonumber\pgf@yy}% }% {% {\pgf@sys@tonumber\pgf@xa}{\pgf@sys@tonumber\pgf@ya}% }% }% \expandafter\pgfutilsolvetwotwoleq\pgfplots@loc@TMPa \def\pgfplots@loc@TMPb##1##2{% \def\pgfplots@view@dir@threedim@x{##1}% \def\pgfplots@view@dir@threedim@y{##2}% }% \expandafter\pgfplots@loc@TMPb\pgfmathresult % % Identify if we need to switch the sign. % To verify that these cases are useful, I suggest visualizing % that stuff using the TeX code from above... % % I guess it is correct up to collapsing views (as you see, I % did not properly identify the cases with "=0" ) \def\pgfplots@scale{1}% \ifdim\pgf@xx>0pt \ifdim\pgf@yx<0pt \else % \ifdim\pgf@xy<0pt \else \ifdim\pgf@yy<0pt \def\pgfplots@scale{-1}% \fi \fi % \fi \else \ifdim\pgf@xx<0pt \ifdim\pgf@yx>0pt \else % \ifdim\pgf@xy>0pt \else \ifdim\pgf@yy>0pt \def\pgfplots@scale{-1}% \fi \fi % \fi \fi \fi \ifdim\pgf@xy>0pt \ifdim\pgf@yy<0pt \else % \ifdim\pgf@xx>0pt \else \ifdim\pgf@yx>0pt \def\pgfplots@scale{-1}% \fi \fi % \fi \else \ifdim\pgf@xy<0pt \ifdim\pgf@yy>0pt \else % \ifdim\pgf@xx<0pt \else \ifdim\pgf@yx<0pt \def\pgfplots@scale{-1}% \fi \fi % \fi \fi \fi \pgfmathmultiply@{\pgfplots@scale}{\pgfplots@view@dir@threedim@x}% \let\pgfplots@view@dir@threedim@x\pgfmathresult \pgfmathmultiply@{\pgfplots@scale}{\pgfplots@view@dir@threedim@y}% \let\pgfplots@view@dir@threedim@y\pgfmathresult \pgfmathmultiply@{\pgfplots@scale}{\pgfplots@view@dir@threedim@z}% \let\pgfplots@view@dir@threedim@z\pgfmathresult % \pgfplotsmathvectorfromstring{\pgfplots@view@dir@threedim@x,\pgfplots@view@dir@threedim@y,\pgfplots@view@dir@threedim@z}{default}% \let\pgfplots@view@dir@threedim=\pgfplotsretval % normalize. This is not absolutely required -- but it is used % to accumulate point depth (for the mesh handler) in pgfmath % arithmetics. At least \pgfplotsmathviewdepthxyz should use % a properly scaled view dir. \pgfplotsmathvectorlength{\pgfplotsretval}{default}% \pgfplotscoordmath{default}{op}{reciprocal}{{\pgfplotsretval}}% \pgfplotsmathvectorscale{\pgfplots@view@dir@threedim}{\pgfmathresult}{default}% \else \pgfplotsmathvectorfromstring{\pgfplots@view@dir@threedim}{default}% \fi % \pgfmath@smuggleone\pgfplotsretval \endgroup \let\pgfplots@view@dir@threedim=\pgfplotsretval \else \def\pgfplots@loc@TMPb##1##2##3{% \pgfplotsmathvectorfromstring{##1,##2,##3}{default}% \let\pgfplots@view@dir@threedim=\pgfplotsretval }% \expandafter\pgfplots@loc@TMPb\pgfplots@loc@TMPc \fi }% % PRECONDITION: % none % POSTCONDITION: % \pgfplots@default@aspect@ratio is set. \def\pgfplots@compute@default@aspect@ratio{% \expandafter\pgfmath@x\axisdefaultwidth \expandafter\pgfmath@y\axisdefaultheight \pgfmathlog@invoke@expanded\pgfmathdivide@{% {\pgf@sys@tonumber{\pgfmath@x}}% {\pgf@sys@tonumber{\pgfmath@y}}% }% \let\pgfplots@default@aspect@ratio=\pgfmathresult } \def\pgfplots@ifneeds@one@uniform@datascale#1#2{% \if3\pgfplots@scale@mode@choice % scale mode=scale uniformly \def\pgfplots@loc@TMPa{1}% % % if we have at least one unit vector given explicitly, the % meaning changes: in that case, we can (and probably should) % use different data scale factors in each direction. \ifx\pgfplots@x\pgfutil@empty \else \def\pgfplots@loc@TMPa{0}% \fi \ifx\pgfplots@y\pgfutil@empty \else \def\pgfplots@loc@TMPa{0}% \fi \ifx\pgfplots@z\pgfutil@empty \else \def\pgfplots@loc@TMPa{0}% \fi \else \def\pgfplots@loc@TMPa{0}% \fi \if1\pgfplots@loc@TMPa #1% \else #2% \fi }% \def\pgfplots@set@default@size@options{% % The axes 'x' and 'y' vectors will be scaled such that the total % size is (\axisdefaultwidth, \axisdefaultheight). % % If the user specifies ONE of width OR height, % the plot will be resized; keeping the aspect ratio. % \let\pgfplots@default@aspect@ratio=\pgfutil@empty \pgfkeysgetvalue{/pgfplots/x}{\pgfplots@x}% \pgfkeysgetvalue{/pgfplots/y}{\pgfplots@y}% \pgfkeysgetvalue{/pgfplots/z}{\pgfplots@z}% %\pgfkeysgetvalue{/pgfplots/viewdir}{\pgfplots@viewdir}% \pgfkeysgetvalue{/pgfplots/width}{\pgfplots@width}% \pgfkeysgetvalue{/pgfplots/height}{\pgfplots@height}% \ifx\pgfplots@width\pgfutil@empty \def\pgfplots@user@provided@width{0}% \else \def\pgfplots@user@provided@width{1}% \pgfmathparse{\pgfplots@width}% \edef\pgfplots@width{\pgfmathresult pt}% \fi \ifx\pgfplots@height\pgfutil@empty \def\pgfplots@user@provided@height{0}% \else \def\pgfplots@user@provided@height{1}% \pgfmathparse{\pgfplots@height}% \edef\pgfplots@height{\pgfmathresult pt}% \fi % % CASES: % W := 'width' option non-empty % H := 'height' option non-empty % % W H % 0 0 -> \axisdefaultwidth % 0 1 -> determine width out of H and the default aspect ratio % 1 X -> ok, use the user parameter. % -> KEEP ASPECT RATIO if just one W, or H is given! \ifx\pgfplots@width\pgfutil@empty \ifx\pgfplots@height\pgfutil@empty % The case W=0 H=0: \let\pgfplots@width=\axisdefaultwidth \let\pgfplots@height=\axisdefaultheight \else % The case W=0 H=1: \pgfplots@compute@default@aspect@ratio \expandafter\pgfmath@y\pgfplots@height \pgfmathlog@invoke@expanded\pgfmathmultiply@{% {\pgf@sys@tonumber{\pgfmath@y}}% {\pgfplots@default@aspect@ratio}% }% \edef\pgfplots@width{\pgfmathresult pt}% \fi \else \ifx\pgfplots@height\pgfutil@empty % The case W=1 H=0: \pgfplots@compute@default@aspect@ratio \expandafter\pgfmath@x\pgfplots@width \pgfmathlog@invoke@expanded\pgfmathdivide@{% {\pgf@sys@tonumber{\pgfmath@x}}% {\pgfplots@default@aspect@ratio}% }% \edef\pgfplots@height{\pgfmathresult pt}% \else % The case W=1 H=1: \fi \fi \pgfkeyslet{/pgfplots/width}{\pgfplots@width}% \pgfkeyslet{/pgfplots/height}{\pgfplots@height}% % \ifpgfplots@threedim \pgfplots@set@default@size@options@threedim \fi % \pgfplots@set@scale@mode } % This method must be called BEFORE THE DATASCALING is initialized. \def\pgfplots@set@scale@mode{% \pgfkeysgetvalue{/pgfplots/unit vector ratio}\pgfplots@loc@TMPb \ifx\pgfplots@loc@TMPb\pgfutil@empty \else \ifcase\pgfplots@scale@mode@choice % 'scale mode'=auto \def\pgfplots@scale@mode@choice{3}% set to 'scale uniformly' % \if1\pgfplots@compat@scale@mode@compatible@mode % backwards compatibility mode... \ifpgfplots@threedim % ... for 3d: there is no backwards compatibility % mode here; it was plain wrong for 3d axes: % neither lengths nor angles have been correct. \pgfplots@compat@scale@mode@compatible@mode@warning \fi \fi \or % scale mode=none: keep it this way. \immediate\write-1{PGFPlots: scale mode=none and unit vector ratio is incompatible. Ignoring unit vector ratio.^^J}% \or % scale mode=stretch to fill \immediate\write-1{PGFPlots: scale mode=stretch to fill and unit vector ratio might produce unexpected results. Consider using scale mode=auto^^J}% \fi \fi % } \def\pgfplots@compat@scale@mode@compatible@mode@warning{% \pgfplotswarning{axis equal incompatible change}\pgfeov% }% \def\pgfplots@set@default@size@options@threedim{% \pgfplots@loc@tmpfalse \ifx\pgfplots@x\pgfutil@empty \else \pgfplots@loc@tmptrue \fi \ifx\pgfplots@y\pgfutil@empty \else \pgfplots@loc@tmptrue \fi \ifx\pgfplots@z\pgfutil@empty \else \pgfplots@loc@tmptrue \fi \ifpgfplots@loc@tmp % oh - we have at least one of the [xyz] unit vectors! % make sure all of them are there \ifx\pgfplots@x\pgfutil@empty \pgfplots@set@default@size@options@threedim@{x}{(1pt,0pt)}% \fi \ifx\pgfplots@y\pgfutil@empty \pgfplots@set@default@size@options@threedim@{y}{(0pt,1pt)}% \fi \ifx\pgfplots@z\pgfutil@empty \pgfplots@set@default@size@options@threedim@{z}{(0pt,1pt)}% \fi \pgfkeyslet{/pgfplots/view/az}\pgfutil@empty \pgfkeyslet{/pgfplots/view/el}\pgfutil@empty \fi } \def\pgfplots@set@default@size@options@threedim@#1#2{% \pgfplots@error{Sorry, a 3D axis needs either NONE or ALL of "x,y,z". I found partial information, but (at least) '#1' is lacking... please add '#1'}% \expandafter\def\csname pgfplots@#1\endcsname{#2}% } % A helper method for \pgfplots@initsizes which % - applies the data scaling trafo to user arguments % - sets calls pgfset#1vec % % #1: the vector to set (either 'x' or 'y') % #2: the index of the vector to set (either 0 or 1) % #3: the already precomputed temporary scale (see pgfplots@initsizes) % #4: an output argument. It is a macro name which will be defined to % '1' if and only if the finally set vector is parallel to the #1 axis % of PGF, that means (x,0) for #1=x and (0,y) for #2=y. \def\pgfplots@initsizes@setunitvector#1#2#3#4{% \pgfkeysgetvalue{/pgfplots/#1 dir/value}\pgfplots@loc@dirvalue \expandafter\let\expandafter\pgfplots@loc@TMPb\csname pgfplots@#1\endcsname \ifx\pgfplots@loc@TMPb\pgfutil@empty \def#4{1}% we have (#1,0) or (0,#1) % %\message{Setting unitvector(#1) to auto-computed multiple of e_#2 ...}% \edef\pgfplots@loc@TMPa{#3}% \if r\pgfplots@loc@dirvalue \edef\pgfplots@loc@TMPa{-#3}% \fi \ifcase#2\relax \pgfsetxvec{\pgfqpoint{\pgfplots@loc@TMPa pt}{0pt}}% \or \pgfsetyvec{\pgfqpoint{0pt}{\pgfplots@loc@TMPa pt}}% \or \pgfsetzvec{\pgfqpoint{\pgfplots@loc@TMPa pt}{\pgfplots@loc@TMPa pt}}% \fi \else % Ok, we have a user-defined unit vector. % % That means we also need to apply the scaling trafo! % % 1. Check whether we have a complete vector of type (x,y): \expandafter\pgfutil@in@\expandafter(\expandafter{\pgfplots@loc@TMPb}% \ifpgfutil@in@ % YES: we have (x,y): % \def#4{0}% we DON'T have (#1,0) or (0,#1). At least I think so. % %\message{Setting unitvector(#1) to non-standard \csname pgfplots@#1\endcsname ...}% \def\pgfplots@loc@TMPa(##1,##2){% \pgfplotscoordmath{default}{parse}{##1}% \pgfplotscoordmath{default}{tofixed}{\pgfmathresult}% \let\pgfplots@loc@TMPb=\pgfmathresult \pgfplotscoordmath{default}{parse}{##2}% \pgfplotscoordmath{default}{tofixed}{\pgfmathresult}% \let\pgfplots@loc@TMPc=\pgfmathresult % \pgfplots@if{pgfplots@apply@datatrafo@#1}{% \pgfplotscoordmath{#1}{datascaletrafo noshift inverse to fixed}{\pgfplots@loc@TMPb}% \let\pgfplots@loc@TMPb=\pgfmathresult \pgfplotscoordmath{#1}{datascaletrafo noshift inverse to fixed}{\pgfplots@loc@TMPc}% \let\pgfplots@loc@TMPc=\pgfmathresult }{}% \csname pgfset#1vec\endcsname{% \pgfqpoint {\if r\pgfplots@loc@dirvalue -\fi\pgfplots@loc@TMPb pt} {\if r\pgfplots@loc@dirvalue -\fi\pgfplots@loc@TMPc pt}}% }% \expandafter\pgfplots@loc@TMPa\pgfplots@loc@TMPb% % \else % NO we simply have a scalar value. \def#4{1}% we have (#1,0) or (0,#1) %\message{Setting unitvector(#1) to \csname pgfplots@#1\endcsname * e_{#2}...}% \pgfplots@if{pgfplots@apply@datatrafo@#1}{% \pgfplotscoordmath{default}{parse}{\csname pgfplots@#1\endcsname}% \pgfplotscoordmath{default}{tofixed}{\pgfmathresult}% \pgfplotscoordmath{#1}{datascaletrafo noshift inverse to fixed}{\pgfmathresult}% \edef\pgfplots@loc@TMPb{\pgfmathresult pt}% }{\relax}% \edef\pgfplots@loc@TMPb{\if r\pgfplots@loc@dirvalue -\fi\pgfplots@loc@TMPb}% \begingroup \pgf@xa=\pgfplots@loc@TMPb\relax \xdef\pgfplots@glob@TMPb{\pgf@sys@tonumber{\pgf@xa}}% \endgroup \ifcase#2\relax \pgfsetxvec{\pgfqpoint{\pgfplots@loc@TMPb}{0pt}}% \or \pgfsetyvec{\pgfqpoint{0pt}{\pgfplots@loc@TMPb}}% \or \pgfsetzvec{\pgfqpoint{\pgfplots@loc@TMPb}{\pgfplots@loc@TMPb}}% \fi \fi \fi %\message{-> got unitvector(#1) = (\the\csname pgf@#1x\endcsname, \the\csname pgf@#1y\endcsname).^^J}% }% % Applies the 'axis equal' feature. % % PRECONDITION: % - #1, #2, #3 contains the current scaling % factors in x,y, z, resp. which are to be applied to unit vectors % - neither unit vectors nor limits are in their final shape % - \pgfplots@set@default@size@options has been invoked before % % POSTCONDITION: % - #1, #2, #3 have been changed to accomodate unit vector ratio % - #4, #5, #6 [output] contain axis limit compensation scales % % There is just one algorithmic difficulty: the data scaling % transformation. All unit vector length above are only meaningful in % the UNTRANSFORMED range, so we have to mingle with the scaling % transformation. \def\pgfplots@apply@unit@ratio#1#2#3#4#5#6{% \begingroup \edef\pgfplots@target@unit@scale@inv@x{#1}% \edef\pgfplots@target@unit@scale@inv@y{#2}% \edef\pgfplots@target@unit@scale@inv@z{#3}% \def\pgfplots@target@limitrescale@x@{1}% \def\pgfplots@target@limitrescale@y@{1}% \def\pgfplots@target@limitrescale@z@{1}% % \pgfkeysgetvalue{/pgfplots/unit vector ratio}\pgfplots@unit@vector@ratio \ifx\pgfplots@unit@vector@ratio\pgfutil@empty \else \edef\pgfplots@unit@vector@ratio{\pgfplots@unit@vector@ratio\space1 1 }% % \expandafter\pgfplots@unit@vector@ratio@check@nop\pgfplots@unit@vector@ratio\pgfplots@EOI \ifpgfplots@loc@tmp % % Step 1: compute the unit vector which STAYS CONSTANT. % \pgfkeysgetvalue{/pgfplots/unit vector ratio axis}\pgfplots@apply@unit@ratio@reference \ifx\pgfplots@apply@unit@ratio@reference\pgfutil@empty \pgfplots@apply@unit@ratio@find@reference% \fi % % FIXME : I could spent some attention here to save work: % both, unit ratios and the resulting scales are computed at % least twice (once in \pgfplots@apply@unit@ratio@find@reference and once in the % following). \expandafter\pgfplots@apply@unit@ratio@prepareratios\pgfplots@unit@vector@ratio\pgfplots@EOI % %\message{USING REFERENCE UNIT VECTOR FROM \pgfplots@apply@unit@ratio@reference; ratio \pgfplots@unit@ratio@x\space \pgfplots@unit@ratio@y\space \pgfplots@unit@ratio@z.^^J}% % % Step 2: apply the scaling: \pgfplots@rescale@unit@vector@reltoreference{x}{\pgfplots@unit@ratio@x}% \pgfplots@rescale@unit@vector@reltoreference{y}{\pgfplots@unit@ratio@y}% \ifpgfplots@threedim \pgfplots@rescale@unit@vector@reltoreference{z}{\pgfplots@unit@ratio@z}% \fi % \else %\message{Skipped application of 'unit vector ratio=\pgfkeysvalueof{/pgfplots/unit vector ratio}': it is already done by 'scale uniformly'.^^J}% \fi \fi \xdef\pgfplots@glob@TMPa{% \noexpand\def\noexpand#1{\pgfplots@target@unit@scale@inv@x}% \noexpand\def\noexpand#2{\pgfplots@target@unit@scale@inv@y}% \noexpand\def\noexpand#3{\pgfplots@target@unit@scale@inv@z}% \noexpand\def\noexpand#4{\pgfplots@target@limitrescale@x@}% \noexpand\def\noexpand#5{\pgfplots@target@limitrescale@y@}% \noexpand\def\noexpand#6{\pgfplots@target@limitrescale@z@}% }% \endgroup \pgfplots@glob@TMPa }% \def\pgfplots@appy@unit@ratio@reciprocal#1{% \pgfplotscoordmath{default}{parsenumber}{#1}% \pgfplotscoordmath{default}{op}{reciprocal}{{\pgfmathresult}}% \pgfplotscoordmath{default}{tofixed}{\pgfmathresult}% }% % Defines \ifpgfplots@loc@tmp := need to modify scaling factors \def\pgfplots@unit@vector@ratio@check@nop#1 #2 #3 #4\pgfplots@EOI{% \pgfplots@loc@tmptrue \if3\pgfplots@scale@mode@choice % scale mode=scale uniformly \ifpgfplots@threedim \ifdim#1pt=#2pt \ifdim#1pt=#3pt % 'axis equal' is implicitly done by 'scale mode=scale % uniformly' anyway \pgfplots@loc@tmpfalse \fi \fi \else \ifdim#1pt=#2pt % 'axis equal' is implicitly done by 'scale mode=scale % uniformly' anyway \pgfplots@loc@tmpfalse \fi \fi \fi % activate the following line to deactivate optimization: [FIXME] %\pgfplots@loc@tmpfalse }% % This macro determines the reference axis for unit vector rescaling. % The reference axis remains unscaled (it gets scaling factor 1 if you % want it this way). % % The other axes are scaled such that the desired unit vector ratios % are fulfilled. % % The idea to select a reference axis is as follows: % 1. Every unit vector scaling factor s should fulfill s <= 1. % 2. Choose the reference axis such that the minimal amount of scaling % is performed. % % The motivation for (1) is: if all involved scaling factors are at % most 1, the resulting picture will only become *smaller*. % Consequently, we can simply enlarge axis limits to restore the % original width/height! % % The motivation for (2) is: a huge amount of scaling might reduce the % size of the image too much. Of course, the figure will be enlarged % to fit the original width/height, but most of it will be empty. So, % use the smallest scaling. % % @POSTCONDITION The reference axis is stored in % \pgfplots@apply@unit@ratio@reference . % % @see the key 'unit vector ratio axis=y' which allows to manually % select the reference axis. This will illustrate what happens here. \def\pgfplots@apply@unit@ratio@find@reference{% % \begingroup \let\pgfplots@ONE=\pgf@x \global\pgfplots@ONE=1.002pt % \def\pgfplots@optimum@sofar@axis{}% \let\pgfplots@optimum@sofar@value=\pgf@y \global\pgfplots@optimum@sofar@value=16000pt % %\pgfplots@apply@unit@ratio@find@reference@checkexplicitlimits % \ifx\pgfplots@optimum@sofar@axis\pgfutil@empty % set \pgfplots@loc@TMPa := 1 if and only if the axis is 3d \def\pgfplots@loc@TMPa{0}% \if0\b@pgfplots@unitvec@is@zero@z % ah, it IS 3d! \def\pgfplots@loc@TMPa{1}% \else % ok, 2d mode (includes view={0}{90}) \def\pgfplots@loc@TMPa{0}% \fi \if1\pgfplots@loc@TMPa % 3D is more complicated than 2D: % for every fixed reference axis, we have to check *two* % scaling factors. % % Furthermore, the optimality condition (2) needs to be % performed on the maximum max{1-s_a, 1-s_b} provided both of % these numbers are positive. % \def\pgfplots@check@##1##2{% % PRECONDITION: \pgfplots@apply@unit@ratio@reference is defined. % % renormalize \pgfplots@unit@[xyz] : \expandafter\pgfplots@apply@unit@ratio@prepareratios\pgfplots@unit@vector@ratio\pgfplots@EOI % % compute s_a : \pgfplots@getscale@unit@vector@reltoreference ##1{\csname pgfplots@unit@ratio@##1\endcsname}% \let\pgfplots@scale@a=\pgfmathresult % % compute s_b : \pgfplots@getscale@unit@vector@reltoreference ##2{\csname pgfplots@unit@ratio@##2\endcsname}% \let\pgfplots@scale@b=\pgfmathresult % % check if the actual choice of % \pgfplots@apply@unit@ratio@reference is FEASIBLE. % That is the case if s_a <= 1 && s_b <= 1. % We check % (1 - s_a >= 0 ) && ( 1 - s_b >= 0 ) % instead, since I need the value % max( 1-s_a, 1-s_b ) % anyway. \def\pgfplots@ref@is@feasible{1}% \pgf@xa=\pgfplots@ONE \advance\pgf@xa by-\pgfplots@scale@a pt \ifdim\pgf@xa<0sp \def\pgfplots@ref@is@feasible{0}% \else \pgf@xb=\pgfplots@ONE \advance\pgf@xb by-\pgfplots@scale@b pt \ifdim\pgf@xb<0sp \def\pgfplots@ref@is@feasible{0}% \fi \fi % compute max(1-s_a,1-s_b) into \pgf@xa: % pgf@xa= max(pgf@xa,pgf@xb): \ifdim\pgf@xb>\pgf@xa \pgf@xa=\pgf@xb \fi \if1\pgfplots@ref@is@feasible \ifdim\pgf@xa<\pgfplots@optimum@sofar@value % Ah, ok. The actual choice is BETTER as it % involves less scaling. % % Remember it! \let\pgfplots@optimum@sofar@axis=\pgfplots@apply@unit@ratio@reference \global\pgfplots@optimum@sofar@value=\pgf@xa \fi \fi %\message{^^Junit vector ratio 3D searching reference: checking \pgfplots@apply@unit@ratio@reference. feasable=\pgfplots@ref@is@feasible. \if1\pgfplots@ref@is@feasible max=\the\pgf@xa. \fi Optimum so far: value =\the\pgfplots@optimum@sofar@value\space for axis \pgfplots@optimum@sofar@axis.^^J}% }% % % Check 'x' as reference : \def\pgfplots@apply@unit@ratio@reference{x}% \pgfplots@check@ yz% % % Check 'y' as reference : \def\pgfplots@apply@unit@ratio@reference{y}% \pgfplots@check@ xz% % % Check 'z' as reference : \def\pgfplots@apply@unit@ratio@reference{z}% \pgfplots@check@ xy% % \else % 2D is much simpler: find the scale s which fulfills s <= 1. % One of them MUST fulfill it. % % try 'x' axis as reference: \def\pgfplots@apply@unit@ratio@reference{x}% % % renormalize: \expandafter\pgfplots@apply@unit@ratio@prepareratios\pgfplots@unit@vector@ratio\pgfplots@EOI % % compute scaling factor: \pgfplots@getscale@unit@vector@reltoreference y\pgfplots@unit@ratio@y% % %\message{^^Junit vector ratio 2D searching reference: checking \pgfplots@apply@unit@ratio@reference. feasable=\pgfmathresult < 1: \ifdim\pgfmathresult pt <\pgfplots@ONE YES-> use x\else NO->use y\fi^^J}% % and check (1). The condition (2) is irrelevant; it is met % anyway. \ifdim\pgfmathresult pt<\pgfplots@ONE \def\pgfplots@optimum@sofar@axis{x}% \else \def\pgfplots@optimum@sofar@axis{y}% \fi \fi \else %\message{^^Junit vector ratio chose \pgfplots@optimum@sofar@axis\space to fulfill explicitly provided limits (at least partially).^^J}% \fi % \ifx\pgfplots@optimum@sofar@axis\pgfutil@empty \if1\b@pgfplots@unitvec@is@zero@z \def\pgfplots@optimum@sofar@axis{y}% \else \def\pgfplots@optimum@sofar@axis{z}% \fi \pgfplotswarning{unit vector ratio axis undetermined}{\pgfplots@optimum@sofar@axis}\pgfeov% \fi \let\pgfplots@apply@unit@ratio@reference=\pgfplots@optimum@sofar@axis \pgfmath@smuggleone\pgfplots@apply@unit@ratio@reference \endgroup }% \def\pgfplots@apply@unit@ratio@find@reference@checkexplicitlimits{% \ifpgfplots@autocompute@ymax \else \def\pgfplots@optimum@sofar@axis{y}\fi \ifpgfplots@autocompute@ymin \else \def\pgfplots@optimum@sofar@axis{y}\fi \ifpgfplots@autocompute@xmax \else \def\pgfplots@optimum@sofar@axis{x}\fi \ifpgfplots@autocompute@xmin \else \def\pgfplots@optimum@sofar@axis{x}\fi \ifpgfplots@threedim \ifpgfplots@autocompute@zmax \else \def\pgfplots@optimum@sofar@axis{z}\fi \ifpgfplots@autocompute@zmin \else \def\pgfplots@optimum@sofar@axis{z}\fi \fi }% % This is ONLY applied to the value of 'unit vector ratio'. It does % not touch the current axis scaling factors. \def\pgfplots@apply@unit@ratio@prepareratios#1 #2 #3 #4\pgfplots@EOI{% \def\pgfplots@unit@ratio@x{#1}% \def\pgfplots@unit@ratio@y{#2}% \def\pgfplots@unit@ratio@z{#3}% % % 'unit vector ratio' is measured relative to the y axis for 2d % and relative to the z axis for 3d plots. % renormalize such that it is relative to % \pgfplots@apply@unit@ratio@reference. % % Furthermore, renormalize such that % unit@ratio@\pgfplots@apply@unit@ratio@reference is 1. \pgfmathreciprocal@{\csname pgfplots@unit@ratio@\pgfplots@apply@unit@ratio@reference\endcsname}% \let\pgfplots@loc@TMPa=\pgfmathresult \ifpgfplots@threedim \if z\pgfplots@apply@unit@ratio@reference \else \pgfmathmultiply@{\pgfplots@loc@TMPa}{\pgfplots@unit@ratio@z}% \let\pgfplots@loc@TMPa=\pgfmathresult \fi % \pgfmathmultiply@{\pgfplots@loc@TMPa}{\pgfplots@unit@ratio@x}% \let\pgfplots@unit@ratio@x=\pgfmathresult % \pgfmathmultiply@{\pgfplots@loc@TMPa}{\pgfplots@unit@ratio@y}% \let\pgfplots@unit@ratio@y=\pgfmathresult % \pgfmathmultiply@{\pgfplots@loc@TMPa}{\pgfplots@unit@ratio@z}% \let\pgfplots@unit@ratio@z=\pgfmathresult \else \if y\pgfplots@apply@unit@ratio@reference \else \pgfmathmultiply@{\pgfplots@loc@TMPa}{\pgfplots@unit@ratio@y}% \let\pgfplots@loc@TMPa=\pgfmathresult \fi % \pgfmathmultiply@{\pgfplots@loc@TMPa}{\pgfplots@unit@ratio@x}% \let\pgfplots@unit@ratio@x=\pgfmathresult % \pgfmathmultiply@{\pgfplots@loc@TMPa}{\pgfplots@unit@ratio@y}% \let\pgfplots@unit@ratio@y=\pgfmathresult % \def\pgfplots@unit@ratio@z{}% \fi % }% % Computes a new unit vector E_#1 for direction #1 such that % ||E_#1|| = #2 * ||e_reference||. % Here, #2 is a scaling factor and e_reference is a reference axis. % The reference axis is stored in % \pgfplots@apply@unit@ratio@reference, the macro contains one of % {x,y,z}. % % The data limits for '#1' will be enlarged as well (for 'unit rescale % keep size'). % % #1 is the axis which should be scaled (i.e. #1 in {x,y,z}). % It is allowed if #1 = \pgfplots@apply@unit@ratio@reference. In this % case, you can provide a scale '#2' to rescale the axis. % % #2 is a desired scale, relative to % \pgfplots@apply@unit@ratio@reference. #2 should be a number without % unit. % % The parameter \pgfplots@apply@unit@ratio@reference is also one of % {x,y,z}. % \def\pgfplots@rescale@unit@vector@reltoreference#1#2{% \def\pgfplots@loc@TMPa{0}% \if#1\pgfplots@apply@unit@ratio@reference \pgfplotsmath@ifapproxequal@dim{#2pt}{1pt}{0.0002pt}{% }{% \def\pgfplots@loc@TMPa{1}% }% \else \def\pgfplots@loc@TMPa{1}% \fi \if1\csname b@pgfplots@unitvec@is@zero@#1\endcsname \def\pgfplots@loc@TMPa{0}% \fi \if1\pgfplots@loc@TMPa % \pgfplots@getscale@unit@vector@reltoreference{#1}{#2}% \global\let\pgfplots@glob@TMPa=\pgfmathresult % %\message{Rescaling '#1' by \pgfplots@glob@TMPa.^^J}% % \pgfmathdivide@{\csname pgfplots@target@unit@scale@inv@#1\endcsname}{\pgfplots@glob@TMPa}% \expandafter\let\csname pgfplots@target@unit@scale@inv@#1\endcsname=\pgfmathresult % \pgfmathreciprocal@\pgfplots@glob@TMPa \expandafter\let\csname pgfplots@target@limitrescale@#1@\endcsname=\pgfmathresult % \fi } % Updates the #1 axis limits such that the axis' dimensions % stay the same after scaling the #1 unit vector by a scale 's'. % % PRECONDITION: % - the #1 unit vector has been rescaled by a factor s. % For example, e_xnew := e_x * 0.5 . % % POSTCONDITION: % - the axis limits are enlarged by a factor 1/s such that % 1/s (#1max - #1min) * e_xnew = (#1max- #1min) * e_x. % % In other words, the unit vector rescale is componensated by % modifying the axis limits: we want to add an absolute component 'd' % to the range: % 1/s (xmax - xmin ) = xmax - xmin +d % => % d = (1/s - 1) * (xmax - xmin) % % The only remaining thing to do is to distribute 'd' to 'xmax' and % 'xmin'. Typically, 50% to each will be fine, I guess... % % #1: either x, y or z. It denotes the direction which has been % modified. % #2: the INVERSE of the scaling factor, #2 = 1/s . % \def\pgfplots@apply@unit@vector@rescale@keep@size#1#2{% \ifdim#2pt=1pt \else \if0\pgfplots@unit@vector@rescale@keep@size % unit rescale keep size=false : do nothing. Ignore the % scaling request. \else % unit rescale keep size=true|unless limits declared % %\message{'unit rescale keep size': Resizing data range for #1 by #2: from \csname pgfplots@#1min\endcsname:\csname pgfplots@#1max\endcsname\ to}% \pgfmathsubtract@{\csname pgfplots@#1max\endcsname}{\csname pgfplots@#1min\endcsname}% \begingroup \pgf@xa=\pgfmathresult pt \pgfmathsubtract@{#2}{1.0}% \pgf@xa=\pgfmathresult \pgf@xa% this is 'd' % % \pgfplots@glob@TMPb : will be subtracted from #1min % \pgfplots@glob@TMPc : will be added to #1max \pgfplots@if{pgfplots@autocompute@#1min}{% \pgfplots@if{pgfplots@autocompute@#1max}{% \pgf@xa=0.5 \pgf@xa \xdef\pgfplots@glob@TMPb{\pgf@sys@tonumber{\pgf@xa}}% \xdef\pgfplots@glob@TMPc{\pgfplots@glob@TMPb}% }{% \xdef\pgfplots@glob@TMPb{\pgf@sys@tonumber{\pgf@xa}}% \xdef\pgfplots@glob@TMPc{0.0}% }% }{% \pgfplots@if{pgfplots@autocompute@#1max}{% \xdef\pgfplots@glob@TMPb{0.0}% \xdef\pgfplots@glob@TMPc{\pgf@sys@tonumber{\pgf@xa}}% }{% \if1\pgfplots@unit@vector@rescale@keep@size % unit rescale keep size=true : FORCE % enlargement! \pgf@xa=0.5 \pgf@xa \xdef\pgfplots@glob@TMPb{\pgf@sys@tonumber{\pgf@xa}}% \xdef\pgfplots@glob@TMPc{\pgfplots@glob@TMPb}% \else % unit rescale keep size=unless limits declared: % do not scale - all limits are declared % explicitly \xdef\pgfplots@glob@TMPb{0.0}% \xdef\pgfplots@glob@TMPc{0.0}% \fi }% }% \endgroup \pgfmathsubtract@{\csname pgfplots@#1min\endcsname}{\pgfplots@glob@TMPb}% \expandafter\global\expandafter\let\csname pgfplots@#1min\endcsname=\pgfmathresult \pgfmathadd@{\csname pgfplots@#1max\endcsname}{\pgfplots@glob@TMPc}% \expandafter\global\expandafter\let\csname pgfplots@#1max\endcsname=\pgfmathresult %\message{\csname pgfplots@#1min\endcsname:\csname pgfplots@#1max\endcsname. [- \pgfplots@glob@TMPb; + \pgfplots@glob@TMPc]^^J}% % % Update auxiliary data members: \pgfplots@visphase@notify@changeofcanvaslimits{#1}% \fi \fi }% % #1: an axis which should be scaled % #2: the desired final ratio ||e_#1||/||e_ref|| \def\pgfplots@getscale@unit@vector@reltoreference#1#2{% % % If the datascaling transformation is active (which is almost % everytime the case here), we have a transformation % T^{-1}(x)= 10^scale * x % with different scales for every axis. % % If the datascaling transformation is NOT active, scale is 0 % and T^{-1} = Identity. % % Note that the datascaling transformation also has % translations (shifts). These are not important here. % % Goal: % compute E_#1 such that % #2* || T^{-1} e_ref || = || T^{-1} E_#1 || % where T^{-1} is the data scaling transformation and e_ref the % reference unit vector. Keep in mind that there are % *different* data scaling transformations for each axis. % % We are given e_ref and e_#1 and the desired aspect ratio % between e_ref and E_#1, which is available as #2. % % So: T^{-1} E_#1 := s* T^{-1} e_#1 where % s = #2 * ||T^{-1} e_ref|| / || T^{-1} e_#1 || % = |10^{scale_ref}| / |10^{scale_#1}| * #2 * || e_ref|| / ||e_#1||. % % Then, E_#1 = T ( T^{-1} E_#1 ) = s * e_#1. % % -> compute 's'! % % Part 1: compute % #2 * ||e_ref|| / ||e_#1||. % \def\pgfplots@loc@TMPa{1}% \if1\csname b@pgfplots@unitvec@is@zero@#1\endcsname \def\pgfplots@loc@TMPa{0}% \else \if1\csname b@pgfplots@unitvec@is@zero@\pgfplots@apply@unit@ratio@reference\endcsname \def\pgfplots@loc@TMPa{0}% \fi \fi \if0\pgfplots@loc@TMPa \def\pgfmathresult{16001}% \else % note that x^{-1} / y^{-1} == ( x/y )^{-1} == y/x . % consequently, we can use our @inv@[xyz] values here: \pgfmathdivide@ {\csname pgfplots@target@unit@scale@inv@#1\endcsname}% {\csname pgfplots@target@unit@scale@inv@\pgfplots@apply@unit@ratio@reference\endcsname} \pgfmathmultiply@ {\pgfmathresult}% {#2}% \global\let\pgfplots@glob@TMPa=\pgfmathresult % % also compute 1/s, required as temporary value: %\pgfmathmultiply@ % {\csname pgfplots@\pgfplots@apply@unit@ratio@reference @inverseveclength\endcsname} % {\csname pgfplots@target@unit@scale@#1\endcsname}% %\ifdim#2pt=1pt %\else % \pgfmathdivide@{\pgfmathresult}{#2}% %\fi %\global\let\pgfplots@glob@TMPb=\pgfmathresult % % Part 2: handle data scaling trafo scales: \begingroup \def\pgfplots@tmp@exponentref{0}% \def\pgfplots@tmp@exponentK{0}% \pgfplots@if{pgfplots@apply@datatrafo@\pgfplots@apply@unit@ratio@reference }{% \pgfplots@letcsname{pgfplots@tmp@exponentref}={pgfplots@data@scale@trafo@EXPONENT@\pgfplots@apply@unit@ratio@reference }% }{}% \pgfplots@if{pgfplots@apply@datatrafo@#1}{% \pgfplots@letcsname{pgfplots@tmp@exponentK}={pgfplots@data@scale@trafo@EXPONENT@#1}% }{}% \c@pgf@counta=\pgfplots@tmp@exponentref\relax \advance\c@pgf@counta by-\pgfplots@tmp@exponentK\relax \ifnum\c@pgf@counta=0 \else \pgfplotsmathmultiplypowten@{\pgfplots@glob@TMPa}{\c@pgf@counta}% \global\let\pgfplots@glob@TMPa=\pgfmathresult % \pgfplotsmathmultiplypowten@{\pgfplots@glob@TMPb}{-\c@pgf@counta}% % \global\let\pgfplots@glob@TMPb=\pgfmathresult \fi \xdef\pgfplots@glob@TMPc{\the\c@pgf@counta}% \endgroup \let\pgfmathresult=\pgfplots@glob@TMPa \fi %\message{\string\pgfplots@getscale@unit@vector@reltoreference{#1}{#2} (reference \pgfplots@apply@unit@ratio@reference) = \pgfmathresult.^^J}% } % helper for \pgfplots@check@and@apply@datatrafo@for. \def\pgfplots@compute@number@order@for@trafo@isdimen#1\tocount#2{% \edef\pgfplots@loc@TMPa{\pgf@sys@tonumber{#1}}% \pgfmathfloatparsenumber{\pgfplots@loc@TMPa}% \expandafter\pgfmathfloat@decompose@E\pgfmathresult\relax#2 \advance#2 by1\relax } % helper for \pgfplots@check@and@apply@datatrafo@for. % \def\pgfplots@compute@number@order@for@trafo@isfloat#1\tocount#2{% \pgfmathfloatparsenumber{#1}% \expandafter\pgfmathfloat@decompose@E\pgfmathresult\relax#2\relax \advance#2 by1 } \def\pgfplots@if@is@float@zero#1#2#3{% \pgfmathfloatparsenumber{#1}% \pgfmathfloatgetflags{\pgfmathresult}{\c@pgf@countd}% \ifnum\c@pgf@countd=0 % % ah - it *is* 0.0: #2% \else #3% \fi } % Initialises the data scale transformation such that it is optimal % for direction #1 (using its axis limits and the target scaling size). % % Note that it will not be applied in any way; and it may still be % modified. % % PRECONDITION: % - all axis limits are available in float representation % - \pgfplots@set@default@size@options has been called before % POSTCONDITION: % - the scaling transformation is set up, \def\pgfplots@set@optimal@datatrafo@for@#1{% \pgfplots@if{pgfplots@apply@datatrafo@#1}{% % initialise data scale transformation % T(x) = 10^{q-m} * x % \ifpgfplots@disabledatascaling % this here is a waste of time, because the NO-OP trafo % will be applied to all coordinates. One could really % safe a lot of CPU time when disabledatascaling is enabled... % but it requires so much extra cases; I really don't want % that! \gdef\pgfplots@glob@TMPa{0}% \gdef\pgfplots@glob@TMPb{0}% \else \begingroup \let\data@max@order=\c@pgf@counta \let\data@cur@order=\c@pgf@countb \let\data@dimen=\pgf@xa \let\data@tmp=\pgf@xb \let\data@dimen@order=\c@pgf@countc \let\data@EXPONENT=\c@pgf@countd \expandafter\let\expandafter\pgfplots@display@min@float\csname pgfplots@#1min\endcsname \expandafter\let\expandafter\pgfplots@display@max@float\csname pgfplots@#1max\endcsname \expandafter\let\expandafter\pgfplots@data@min@float\csname pgfplots@data@#1min\endcsname \expandafter\let\expandafter\pgfplots@data@max@float\csname pgfplots@data@#1max\endcsname \ifpgfplots@autocompute@all@limits \else \pgfplotscoordmath{#1}{max}{\pgfplots@display@max@float}{\pgfplots@data@max@float}% \let\pgfplots@data@max@float=\pgfmathresult \pgfplotscoordmath{#1}{min}{\pgfplots@display@min@float}{\pgfplots@data@min@float}% \let\pgfplots@data@min@float=\pgfmathresult \fi % %\message{minmax = [\pgfplots@data@min@float,\pgfplots@data@max@float]^^J}% % Step 1: compute 'm', the data order \pgfplots@if@is@float@zero{\pgfplots@data@min@float}{% \pgfplots@if@is@float@zero{\pgfplots@data@max@float}{% \data@max@order=1 % both are zero. ok. % Note that this is '1' due to backwards % compatibility. }{% % one of them is zero. Take the other one! \pgfplots@compute@number@order@for@trafo@isfloat \pgfplots@data@max@float \tocount\data@cur@order \data@max@order=\data@cur@order }% }{% \pgfplots@if@is@float@zero{\pgfplots@data@max@float}{% % one of them is zero. Take the other one! \pgfplots@compute@number@order@for@trafo@isfloat \pgfplots@data@min@float \tocount\data@cur@order \data@max@order=\data@cur@order }{% % none of them is zero. Compute MAX: \pgfplots@compute@number@order@for@trafo@isfloat \pgfplots@data@min@float \tocount\data@cur@order \data@max@order=\data@cur@order \pgfplots@compute@number@order@for@trafo@isfloat \pgfplots@data@max@float \tocount\data@cur@order \ifnum\data@cur@order>\data@max@order \data@max@order=\data@cur@order \fi }% }% % % % % Step 2: compute 'q', the #1-size of the axis. %\expandafter\ifx\csname pgfplots@#1\endcsname\pgfutil@empty % We have 'width' or 'height' (I always have them). % % Use the order of these parameters. \def\pgfplots@loc@TMPa{#1}% \def\pgfplots@loc@TMPb{x}% \ifx\pgfplots@loc@TMPa\pgfplots@loc@TMPb \data@dimen=\pgfplots@width\relax \else \if1\pgfplots@compat@scaling@zunitfix@enable \data@dimen=\pgfplots@height\relax \else % this code here belongs to versions up to % 1.3.1. % It is now deprecated and produces small % pixel differences. \def\pgfplots@loc@TMPb{y}% \ifx\pgfplots@loc@TMPa\pgfplots@loc@TMPb \data@dimen=\pgfplots@height\relax \else \data@dimen=42pt % this is actually different from 1.3.1: there, it was UNDEFINED. \fi \fi \fi \pgfplots@compute@number@order@for@trafo@isdimen \data@dimen \tocount\data@dimen@order % This here is to avoid inaccuracies in the final % axis rectangle size, see \pgfplots@initsizes: %\advance\data@dimen@order by-1 %\else % FIXME: % we have either the 'x=1cm' or 'y=1cm' option! % How should I initialise the trafo!? % \data@dimen@order=3 %\fi % %\message{Direction #1: data max order=\the\data@max@order; data dimen order=\the\data@dimen@order. ^^J}% \data@EXPONENT=\data@dimen@order \advance\data@EXPONENT by-\data@max@order % Now, I introduce a loop which shall avoid cancellation of % significant digits. % % Harmless Example: % if we have data shift = -3 and % max = 2e6, min = 1e6, then max-min = 1e6; T(max)-T(min) = 1e3 which is ok. % In this case, the loop won't change anything. % % Critical Example: % if we have data shift = -3 and % max = 1980, min = 1930 then % T(max) = 1.98 and T(min) = 1.93 % and thus T(max)-T(min) = 0.05 . % Considering that this is the axis range % in which tick labels and plot points need to be computed, we % only have two or three digits left! That happens because the % prefix '19' is common and is cancelled in the subtraction. % Idea: while T(max)-T(min) < O(10^2) -> increase shift by +1 % (and make sure that T(max) < MAX_VALID_TEX_NUMBER). % \def\pgfplotscoordmathnotifydatascalesetfor##1{}% disable temporarily. We are just testing it. \pgfplots@loop@CONTINUEtrue \pgfutil@loop \pgfplotscoordmath{#1}{datascaletrafo set params}{\the\data@EXPONENT}{0}% \pgfplotscoordmath{#1}{datascaletrafo}{\pgfplots@data@min@float}% \let\pgfplots@min@fixed=\pgfmathresult \ifpgfplots@loop@CONTINUE \pgfplotscoordmath{#1}{datascaletrafo}{\pgfplots@data@max@float}% \let\pgfplots@max@fixed=\pgfmathresult \data@tmp=\pgfplots@max@fixed pt %\message{Current trafo EXPONENT for #1 direction: \the\data@EXPONENT; original #1 data limits: [\pgfplots@data@min@float:\pgfplots@data@max@float]; current transformed #1 limits: [\pgfplots@min@fixed:\pgfplots@max@fixed]; cancellation check max-min running...^^J}% \ifdim\data@tmp<0pt % I need absolute values here: \multiply\data@tmp by-1\relax \fi \pgfmathsubtract@{\pgfplots@max@fixed}{\pgfplots@min@fixed}% \data@dimen=\pgfmathresult pt \pgfplots@loop@CONTINUEfalse \ifdim\data@tmp<1500pt % a multiplication with '10' results in max = 15000 which is the upper limit. \ifdim\data@dimen<100pt % I guess if max-min = O(100), we have quite good accuracy \ifdim\data@dimen<0.0001pt \else \advance\data@EXPONENT by1 \pgfplots@loop@CONTINUEtrue \fi \fi \fi %-------------------------------------------------- % \ifdim\data@dimen>1200pt% FIXME : is this here ok!? CHECK IT! % \ifdim\data@dimen>7999pt % \advance\data@EXPONENT by-2 % \else % \advance\data@EXPONENT by-1 % \fi % \pgfplots@loop@CONTINUEfalse % \fi %-------------------------------------------------- \pgfutil@repeat \xdef\pgfplots@glob@TMPa{\the\data@EXPONENT}% \xdef\pgfplots@glob@TMPb{\pgfplots@min@fixed}% \endgroup \fi % COMPLETE INITIALISATION: %\message{Initialising the data scale transformation in direction #1 to 10^\pgfplots@glob@TMPa*#1 - \pgfplots@glob@TMPb...^^J}% \pgfplotscoordmath{#1}{datascaletrafo set params}{\pgfplots@glob@TMPa}{\pgfplots@glob@TMPb}% }{% % case apply trafo == false: \pgfplotscoordmath{#1}{datascaletrafo set params}{0}{0}% }% } \def\pgfplots@set@optimal@datatrafos@allaxes{% \pgfplots@letcsname pgfplots@xmin@unscaled@as@float={pgfplots@xmin}% \pgfplots@letcsname pgfplots@xmax@unscaled@as@float={pgfplots@xmax}% % \pgfplots@letcsname pgfplots@ymin@unscaled@as@float={pgfplots@ymin}% \pgfplots@letcsname pgfplots@ymax@unscaled@as@float={pgfplots@ymax}% % \pgfplots@letcsname pgfplots@zmin@unscaled@as@float={pgfplots@zmin}% \pgfplots@letcsname pgfplots@zmax@unscaled@as@float={pgfplots@zmax}% % \pgfplots@ifneeds@one@uniform@datascale{% % Ah - we have to ensure that there is ONE common scale for % each unit (x, y, and z have the same). % % In this case, we need to choose one of the transformations % and apply it to all axes -- such that each axis gets the % same scale. % % this mode is used for axis equal and its variants. % % The strategy to fix the transformation is as follows: % 1. we assume that axis limits will be enlarged in order to % satisfy 'scale uniformly'. % 2. we assume that the LARGEST axis limit dominates the % others. % 3. if one of the axes does not have datascaling (i.e. is % log scale), we disable all other datascalings. % % Consequently, we search for the axis with the largest limit % - and copy its data scaling to all other axes. If one of the % axes is log, that one overrules it and all data scaling % effects are disabled.. \ifpgfplots@disabledatascaling \def\pgfplots@loc@TMPd##1{% \pgfplotscoordmath{##1}{datascaletrafo set params}{0}{0}% }% \else \begingroup \let\pgfplots@data@scale@trafo@EXPONENT@common=\pgfutil@empty \ifpgfplots@disabledatascaling \def\pgfplots@data@scale@trafo@EXPONENT@common{{0}{0}}% disable scaling! \fi \def\pgfplots@data@scale@trafo@EXPONENT@common@arg{-}% this should not match anything in this context. \pgfplots@if{pgfplots@apply@datatrafo@x}{% }{% \def\pgfplots@data@scale@trafo@EXPONENT@common{{0}{0}}% disable scaling! }% \pgfplots@if{pgfplots@apply@datatrafo@y}{% }{% \def\pgfplots@data@scale@trafo@EXPONENT@common{{0}{0}}% disable scaling! }% \ifpgfplots@threedim \pgfplots@if{pgfplots@apply@datatrafo@z}{% }{% \def\pgfplots@data@scale@trafo@EXPONENT@common{{0}{0}}% disable scaling! }% \fi \ifx\pgfplots@data@scale@trafo@EXPONENT@common\pgfutil@empty % ah - we still need to compute one. ok, search for the % largest limit. % \pgfplots@get@axis@with@largest@limits \let\pgfplots@data@scale@trafo@EXPONENT@common@arg=\pgfplotsretval % % ok, compute data scaling transformation for the target axis: \expandafter\pgfplots@set@optimal@datatrafo@for@\pgfplots@data@scale@trafo@EXPONENT@common@arg% % \pgfplotscoordmath{\pgfplots@data@scale@trafo@EXPONENT@common@arg}{datascaletrafo get params}% \let\pgfplots@data@scale@trafo@EXPONENT@common=\pgfmathresult% \else % hm. early-out - we already have the scaling trafo. % return it. \fi \global\let\pgfplots@glob@TMPa=\pgfplots@data@scale@trafo@EXPONENT@common \global\let\pgfplots@glob@TMPb=\pgfplots@data@scale@trafo@EXPONENT@common@arg \endgroup % \xdef\pgfplots@glob@TMPc{\expandafter\pgfutil@firstoftwo\pgfplots@glob@TMPa}% % \def\pgfplots@loc@TMPd##1{% \if ##1\pgfplots@glob@TMPb % we need to set the scaling trafo for the target direction % (was lost after \endgroup) \def\pgfplots@loc@TMPa{\pgfplotscoordmath{##1}{datascaletrafo set params}}% \expandafter\pgfplots@loc@TMPa\pgfplots@glob@TMPa% \else \pgfplotscoordmath{##1}{datascaletrafo set params}{\pgfplots@glob@TMPc}{0}% \pgfplotscoordmath{##1}{datascaletrafo}{\csname pgfplots@##1min\endcsname}% \pgfplotscoordmath{##1}{datascaletrafo set params}{\pgfplots@glob@TMPc}{\pgfmathresult}% \fi }% \fi \pgfplots@loc@TMPd x% \pgfplots@loc@TMPd y% \ifpgfplots@threedim \pgfplots@loc@TMPd z% \fi }{% % optimize individually: \pgfplots@set@optimal@datatrafo@for@ x% \pgfplots@set@optimal@datatrafo@for@ y% \ifpgfplots@threedim \pgfplots@set@optimal@datatrafo@for@ z% \fi }% % }% % Defines \pgfplotsretval to be one of x, y, or z, such that the % return value indicates the axis with largest untransformed axis % limits. \def\pgfplots@get@axis@with@largest@limits{% \begingroup \let\pgfplotsretval@extreme=\pgfutil@empty \let\pgfplotsretval@extreme@arg=\pgfutil@empty \def\pgfplots@@##1{% % compute axis range for axis ##1 ... \pgfplotscoordmath{default}{parsenumber}{\csname pgfplots@##1min\endcsname}% \let\pgfplots@loc@TMPa=\pgfmathresult \pgfplotscoordmath{default}{parsenumber}{\csname pgfplots@##1max\endcsname}% \pgfplotscoordmath{default}{op}{subtract}{{\pgfmathresult}{\pgfplots@loc@TMPa}}% % ... ok, it is in \pgfmathresult. \let\candidate=\pgfmathresult \ifx\pgfplotsretval@extreme@arg\pgfutil@empty % ah: no extreme value so far. use ours. \def\pgfplotsretval@extreme@arg{##1}% \let\pgfplotsretval@extreme=\candidate \else \pgfplotscoordmath{default}{if less than}{\pgfplotsretval@extreme}{\candidate}{% % update extreme value: \def\pgfplotsretval@extreme@arg{##1}% \let\pgfplotsretval@extreme=\candidate }{% }% \fi }% \pgfplots@@ x% \pgfplots@@ y% \ifpgfplots@threedim \pgfplots@@ z% \fi \let\pgfplotsretval=\pgfplotsretval@extreme@arg \pgfmath@smuggleone\pgfplotsretval \endgroup }% % Initialises the data scale transformation and applies it to any % user specified options. % % PRECONDITION: % - all axis limits are available in float representation % - \pgfplots@set@default@size@options has been called before % - the scaling transformation for direction x is set up % (\pgfplots@set@optimal@datatrafo@for@), % POSTCONDITION: % - all axis limits are transformed, but no other axis inputs. % % Unit vectors and other axis input parameters will be scaled later. % % @see \pgfplots@check@and@apply@datatrafo@for \def\pgfplots@apply@datatrafo@to@axis@limits#1{% \pgfplots@if{pgfplots@apply@datatrafo@#1}{% % Transform axis limits: %\message{#1- display limits BEFORE data transformation: [\csname pgfplots@#1min\endcsname:\csname pgfplots@#1max\endcsname]^^J}% \pgfplotscoordmath{#1}{datascaletrafo}{\csname pgfplots@#1min\endcsname}% \expandafter\global\expandafter\let\csname pgfplots@#1min\endcsname=\pgfmathresult % \pgfplotscoordmath{#1}{datascaletrafo}{\csname pgfplots@#1max\endcsname}% \expandafter\global\expandafter\let\csname pgfplots@#1max\endcsname=\pgfmathresult %\message{#1- display limits after data transformation: [\csname pgfplots@#1min\endcsname:\csname pgfplots@#1max\endcsname]^^J}% }{% % case apply trafo == false: \expandafter\let\csname pgfplots@#1min@unscaled@as@float\endcsname=\pgfutil@empty \expandafter\let\csname pgfplots@#1max@unscaled@as@float\endcsname=\pgfutil@empty }% }