%-------------------------------------------- % % 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/2008 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 . % %-------------------------------------------- \newif\ifpgfplots@log@tick@isminor@tick@pos % Checks whether the tick position given as #1.#2=log10(T) belongs to % T=i*10^j with an integer i>1. % % If T=i*10^j, \ifpgfplots@log@tick@isminor@tick@pos will be set to true and % \pgfmathresult will contain T. % % Otherwise, \ifpgfplots@log@tick@isminor@tick@pos will be set to false and % pgfmathresult to #1.#2 % % Arguments: % #1.#2 the value log10(T) % % Implementation: % if T = i*10^j, log10(T) = log10(i) + j. % That means if log10(T) in \Z, we have T = 10^j. If not, we need to % check wether i is an integer. Please note that log10(i) < 1. % % Further note: log(T) < 0 <=> j<0. % In case j<0, we have % #1.#2 = j + log(i) % = - ( -j - log(i) ) % = - ( -j - 1 + (1-log(i)) ) % = #1 '.' #2 [ up to the '0.' % that means #1 = j-1 and #2 = 1-log(i). \def\pgfplots@is@log@tick@a@minor@tick@pos#1.#2\relax{% \pgfmathapproxequalto@{#1.#2}{#1.0}% \ifpgfmathcomparison % in MOST cases, this here will be true: \pgfplots@log@tick@isminor@tick@posfalse \def\pgfmathresult{#1.#2}% \else % I guess this won't happen too often. In fact, it's a very % special case. \begingroup \c@pgf@counta=#1\relax \ifnum\c@pgf@counta<0 \advance\c@pgf@counta by-1 \pgfmathsubtract@{1}{0.#2}% \expandafter\pgfplots@is@log@tick@a@minor@tick@pos@IDENTIFY@LOGi\pgfmathresult\relax \ifpgfplots@log@tick@isminor@tick@pos \aftergroup\pgfplots@log@tick@isminor@tick@postrue \edef\pgfmathresult{\pgfmathresult e\the\c@pgf@counta}% \else \aftergroup\pgfplots@log@tick@isminor@tick@posfalse \def\pgfmathresult{#1.#2}% \fi \else \pgfplots@is@log@tick@a@minor@tick@pos@IDENTIFY@LOGi0.#2\relax \ifpgfplots@log@tick@isminor@tick@pos \aftergroup\pgfplots@log@tick@isminor@tick@postrue \edef\pgfmathresult{\pgfmathresult e\the\c@pgf@counta}% \else \aftergroup\pgfplots@log@tick@isminor@tick@posfalse \def\pgfmathresult{#1.#2}% \fi \fi \pgfmath@smuggleone\pgfmathresult \endgroup \fi } % expects a positive number. \def\pgfplots@is@log@tick@a@minor@tick@pos@IDENTIFY@LOGi0.#1\relax{% \pgfplots@log@tick@isminor@tick@postrue \pgfmathapproxequalto@{0.#1}{0.3010299956639}% \ifpgfmathcomparison \def\pgfmathresult{2}% \else \pgfmathapproxequalto@{0.#1}{0.4771212547196}% \ifpgfmathcomparison \def\pgfmathresult{3}% \else \pgfmathapproxequalto@{0.#1}{0.6020599913279}% \ifpgfmathcomparison \def\pgfmathresult{4}% \else \pgfmathapproxequalto@{0.#1}{0.698970004}% \ifpgfmathcomparison \def\pgfmathresult{5}% \else \pgfmathapproxequalto@{0.#1}{0.7781512503}% \ifpgfmathcomparison \def\pgfmathresult{6}% \else \pgfmathapproxequalto@{0.#1}{0.8450980400}% \ifpgfmathcomparison \def\pgfmathresult{7}% \else \pgfmathapproxequalto@{0.#1}{0.9030899869}% \ifpgfmathcomparison \def\pgfmathresult{8}% \else \pgfmathapproxequalto@{0.#1}{0.954242509439}% \ifpgfmathcomparison \def\pgfmathresult{9}% \else \pgfplots@log@tick@isminor@tick@posfalse \fi \fi \fi \fi \fi \fi \fi \fi } % Checks whether we need to create a separate 'tick scale label', % a node with ' * 10^3' on the side of the axis: % % PRECONDITION: % Axis limits for #1 are given. I need their values before any data % scale transformation has been applied. % If % \pgfplots@#1min@unscaled@as@float % and % \pgfplots@#1max@unscaled@as@float % exist; I will use these macros. % Otherwise, I will use \pgfplots@#1min and \pgfplots@#1max; % assuming that no data scale transformation is active. % FIXME : does that need further attention? \def\pgfplots@init@scaled@tick@for#1{% \global\def\pgfplots@glob@TMPa{0}% \begingroup \ifcase\csname pgfplots@scaled@ticks@#1@choice\endcsname % CASE 0 : scaled #1 ticks=false: do nothing here. \or % CASE 1 : scaled #1 ticks=true: %-------------------------------- % the \pgfplots@xmin@unscaled@as@float is set just before the data % scale transformation is initialised. % % The variables are empty if there is no datascale transformation. \expandafter\let\expandafter\pgfplots@cur@min@unscaled\csname pgfplots@#1min@unscaled@as@float\endcsname \expandafter\let\expandafter\pgfplots@cur@max@unscaled\csname pgfplots@#1max@unscaled@as@float\endcsname % \ifx\pgfplots@cur@min@unscaled\pgfutil@empty \edef\pgfplots@loc@TMPa{\csname pgfplots@#1min\endcsname}% \expandafter\pgfmathfloatparsenumber\expandafter{\pgfplots@loc@TMPa}% \let\pgfplots@cur@min@unscaled=\pgfmathresult \edef\pgfplots@loc@TMPa{\csname pgfplots@#1max\endcsname}% \expandafter\pgfmathfloatparsenumber\expandafter{\pgfplots@loc@TMPa}% \let\pgfplots@cur@max@unscaled=\pgfmathresult \fi % \expandafter\pgfmathfloat@decompose@E\pgfplots@cur@min@unscaled\relax\pgfmathfloat@a@E \expandafter\pgfmathfloat@decompose@E\pgfplots@cur@max@unscaled\relax\pgfmathfloat@b@E \ifnum\pgfmathfloat@b@E<\pgfmathfloat@a@E \pgfmathfloat@b@E=\pgfmathfloat@a@E \fi \xdef\pgfplots@glob@TMPa{\pgfplots@scale@ticks@above@exponent}% \expandafter\ifnum\pgfplots@glob@TMPa<\pgfmathfloat@b@E % ok, scale it: \multiply\pgfmathfloat@b@E by-1 \xdef\pgfplots@glob@TMPa{\the\pgfmathfloat@b@E}% \else \xdef\pgfplots@glob@TMPa{\pgfplots@scale@ticks@below@exponent}% \expandafter\ifnum\pgfplots@glob@TMPa>\pgfmathfloat@b@E % ok, scale it: \multiply\pgfmathfloat@b@E by-1 \xdef\pgfplots@glob@TMPa{\the\pgfmathfloat@b@E}% \else % no scaling necessary: \xdef\pgfplots@glob@TMPa{0}% \fi \fi \or % CASE 2 : scaled #1 ticks=base 10: %-------------------------------- \c@pgf@counta=\csname pgfplots@scaled@ticks@#1@arg\endcsname\relax %\multiply\c@pgf@counta by-1 \xdef\pgfplots@glob@TMPa{\the\c@pgf@counta}% \or % CASE 3 : scaled #1 ticks=real: %-------------------------------- \pgfmathfloatparsenumber{\csname pgfplots@scaled@ticks@#1@arg\endcsname}% \global\let\pgfplots@glob@TMPa=\pgfmathresult \or % CASE 4 : scaled #1 ticks=manual: \expandafter\global\expandafter\let\expandafter\pgfplots@glob@TMPa\csname pgfplots@scaled@ticks@#1@arg\endcsname \fi \endgroup \expandafter\let\csname pgfplots@tick@scale@#1\endcsname=\pgfplots@glob@TMPa% } % x-axis tick labels for #1th tick % #1: the axis (x,y or z) % #2: the value % #3,#4: coordinates for \pgfplotspointonorientedsurfaceab % #5: ticknumber \def\pgfplots@show@ticklabel#1#2(#3,#4)#5{% \begingroup% \csname ifpgfplots@#1ticklabel@interval\endcsname % Special case for the INTERVAL feature: % we have to do additional work here. \pgfmathparse{#3}% \edef\pgfplots@show@ticklabel@coord@x@new{\pgfmathresult}% \pgfmathparse{#4}% \edef\pgfplots@show@ticklabel@coord@y@new{\pgfmathresult}% % \pgfplots@show@ticklabel@{#1}{#2}% \let\nexttick=\tick \ifx\pgfplots@show@ticklabel@LASTTICK\pgfutil@empty % its the first call. Simply remember arguments and wait % for interval boundary before proceeding. \else % acquire options of first interval boundary: \pgfplots@show@ticklabel@LASTTICK % compute new node position: \pgfmathparse{0.5*(\pgfplots@show@ticklabel@coord@x + \pgfplots@show@ticklabel@coord@x@new)}% \let\pgfplots@show@ticklabel@coord@x=\pgfmathresult% \pgfmathparse{0.5*(\pgfplots@show@ticklabel@coord@y + \pgfplots@show@ticklabel@coord@y@new)}% \let\pgfplots@show@ticklabel@coord@y=\pgfmathresult% \let\ticknum=\pgfplots@show@ticklabel@num\relax% \let\tick=\pgfplots@show@ticklabel@tick% \pgfplots@show@ticklabel@@{#1}{\pgfplotspointonorientedsurfaceab{\pgfplots@show@ticklabel@coord@x}{\pgfplots@show@ticklabel@coord@y}}% \fi \xdef\pgfplots@show@ticklabel@LASTTICK{% \noexpand\def\noexpand\pgfplots@show@ticklabel@tick{\nexttick}% \noexpand\def\noexpand\pgfplots@show@ticklabel@coord@x{\pgfplots@show@ticklabel@coord@x@new}% \noexpand\def\noexpand\pgfplots@show@ticklabel@coord@y{\pgfplots@show@ticklabel@coord@y@new}% \noexpand\edef\noexpand\pgfplots@show@ticklabel@num{#5}% }% \else \let\ticknum=#5\relax% \pgfplots@show@ticklabel@{#1}{#2}% \pgfplots@show@ticklabel@@{#1}{\pgfplotspointonorientedsurfaceab{#3}{#4}}% \fi \endgroup } % #1: the axis (x,y or z) % #2: the location where to place it. \def\pgfplots@show@ticklabel@@#1#2{% % Typeset the label! \pgfinterruptboundingbox % What makes this complicated is the 'ticklabel cs' feature. % What we need is to compute the MAXIMUM LENGTH over each tick % label IN DIRECTION OF THE OUTER NORMAL. % % This needs to % 1. enable bounding box computation even in case of % 'overlay', % 2. projection of the bounding box in direction of the outer % normal, % 3. update of the bounding box if 'overlay' is not active. \begingroup % % prepare step (1.): \pgfkeysalso{% /tikz/every node/.append code={% \ifpgf@relevantforpicturesize \gdef\pgfplots@show@ticklabel@@update@BB{1}% \else \gdef\pgfplots@show@ticklabel@@update@BB{0}% \fi \pgf@relevantforpicturesizetrue }% }% % % Compute and remember the position '#2': \pgf@process{#2}% \edef\pgfplots@ticklabel@at@x{\the\pgf@x}% \edef\pgfplots@ticklabel@at@y{\the\pgf@y}% % % ok, generate the label! \node at (\pgfplots@ticklabel@at@x,\pgfplots@ticklabel@at@y) {\csname pgfplots@#1ticklabel\endcsname};% % % compute the label's dimensions, step (2.): \pgfplots@ticklabel@maxtickdimen@updateforcurrentpath {#1} {\pgf@x=\pgfplots@ticklabel@at@x\space\pgf@y=\pgfplots@ticklabel@at@y\space}%% % % prepare step (3.): update of bounding box: \if\pgfplots@show@ticklabel@@update@BB1% \xdef\pgfplots@glob@TMPa{% \pgf@xa=\the\pgf@picminx\space \pgf@xb=\the\pgf@picminy\space \pgf@ya=\the\pgf@picmaxx\space \pgf@yb=\the\pgf@picmaxy\space \noexpand\pgf@protocolsizes{\pgf@xa}{\pgf@xb}% \noexpand\pgf@protocolsizes{\pgf@ya}{\pgf@yb}% \noexpand\pgf@resetpathsizes }% \else \global\let\pgfplots@glob@TMPa=\relax \fi \endgroup \endpgfinterruptboundingbox \begingroup \pgfplots@glob@TMPa \endgroup }% % TICK LABEL DIMENSION CONTROL % % The following framework is supposed to accumulate the value for % \pgfplotsvalueoflargesttickdimen. % % It works like this: % % \pgfplots@ticklabel@maxtickdimen@reset{#1} % \pgfplots@ticklabel@maxtickdimen@prepare@for@normalvec{#1}{} % ... % \pgfplots@ticklabel@maxtickdimen@updateforcurrentpath{#1} % \pgfplots@ticklabel@maxtickdimen@updateforcurrentpath{#1} % \pgfplots@ticklabel@maxtickdimen@updateforcurrentpath{#1} % ... % \pgfplots@ticklabel@maxtickdimen@finish{#1} % % -> then, \pgfplotsvalueoflargesttickdimen expands to the largest % distance from a tick's coordinate to its tick label bounding box in % direction of the outer normal vector. \def\pgfplots@ticklabel@maxtickdimen@reset#1{% \expandafter\gdef\csname pgfplots@maxtickdimen@#1\endcsname{0pt}% \expandafter\gdef\csname pgfplots@maxtickdimen@extrashift@#1\endcsname{0pt}% }% % Adds the extra shift '#2' along the normal vector for axis '#1'. \def\pgfplots@ticklabel@maxtickdimen@extrashift#1#2{% \begingroup \afterassignment\pgfplots@gobble@until@relax \pgf@xa=#2pt\relax \advance\pgf@xa by\csname pgfplots@maxtickdimen@extrashift@#1\endcsname\relax \expandafter\xdef\csname pgfplots@maxtickdimen@extrashift@#1\endcsname{\the\pgf@xa}% \endgroup } % Finalizes the maxtickdimen computation. % % This applies any extra shifts (including '#1ticklabel shift'). \def\pgfplots@ticklabel@maxtickdimen@finish#1{% \pgfkeysgetvalue{/pgfplots/#1ticklabel shift}\pgfmathresult \ifx\pgfmathresult\pgfutil@empty \else \pgfplots@ticklabel@maxtickdimen@extrashift{#1}{\pgfkeysvalueof{/pgfplots/#1ticklabel shift}}% \fi \begingroup \pgf@xa=\csname pgfplots@maxtickdimen@extrashift@#1\endcsname\relax \advance\pgf@xa by \csname pgfplots@maxtickdimen@#1\endcsname\relax \expandafter\xdef\csname pgfplots@maxtickdimen@#1\endcsname{\the\pgf@xa}% \endgroup }% % % #1: the axis (x,y or z) % #2: the normal vector \def\pgfplots@ticklabel@maxtickdimen@prepare@for@normalvec#1#2{% \pgf@process{#2}% \edef\pgfplots@loc@vector@to@outside{\pgf@x=\the\pgf@x\space\pgf@y=\the\pgf@y\space}% % Identify the corner point of the ticklabel bounding box which % shall be used: \ifdim\pgf@x>0sp \ifdim\pgf@y>0sp % NORTH EAST \def\pgfplots@loc@ticklabel@bb@corner{\pgf@x=\pgf@picmaxx\pgf@y=\pgf@picmaxy}% \else % SOUTH EAST \def\pgfplots@loc@ticklabel@bb@corner{\pgf@x=\pgf@picmaxx\pgf@y=\pgf@picminy}% \fi \else \ifdim\pgf@y>0sp % NORTH WEST \def\pgfplots@loc@ticklabel@bb@corner{\pgf@x=\pgf@picminx\pgf@y=\pgf@picmaxy}% \else % SOUTH WEST \def\pgfplots@loc@ticklabel@bb@corner{\pgf@x=\pgf@picminx\pgf@y=\pgf@picminy}% \fi \fi }% % #1: the axis (x,y or z) % #2: the point from where dimension shall be computed (the 'at' % argument of the tick label) \def\pgfplots@ticklabel@maxtickdimen@updateforcurrentpath#1#2{% \pgfplotsscalarproductofvectors {\pgfplots@loc@vector@to@outside}% {\pgfpointdiff {#2}% {\pgfplots@loc@ticklabel@bb@corner}}% \ifdim\pgf@x>\csname pgfplots@maxtickdimen@#1\endcsname\relax \expandafter\xdef\csname pgfplots@maxtickdimen@#1\endcsname{\the\pgf@x}% \fi }% % Expands to the largest distance of a tick position to its tick label % bounding box in direction of the outer unit normal vector. % % It does also include the value of the 'ticklabel shift' key. % % This function assumes that % \pgfplots@ticklabel@maxtickdimen@reset{#1} % \pgfplots@ticklabel@maxtickdimen@prepare@for@normalvec{#1}{} % ... % \pgfplots@ticklabel@maxtickdimen@updateforcurrentpath{#1} % \pgfplots@ticklabel@maxtickdimen@updateforcurrentpath{#1} % \pgfplots@ticklabel@maxtickdimen@updateforcurrentpath{#1} % ... % \pgfplots@ticklabel@maxtickdimen@finish{#1} % has been invoked completely. % % #1: either x,y or z. It denotes the axis for which the ticks are % requested. \def\pgfplotsvalueoflargesttickdimen#1{% \csname pgfplots@maxtickdimen@#1\endcsname }% % Just like \pgfplotsqpointoutsideofaxis, but this one here uses the % axis on which tick labels will be drawn. % % #1: one of x, y or z. % #2: the coordinate on the tick axis designated by '#1'. % #3: a scale (a dimen) in which the point is moved in direction of % the outward normal vector of the axis. % % @see \pgfplotsqpointoutsideofaxis \def\pgfplotsqpointoutsideofticklabelaxis#1#2#3{% \pgfplotsqpointoutsideofaxis{\csname pgfplots@#1ticklabelaxisspec\endcsname}{#2}{#3}% }% \def\pgfplotsqpointoutsideofticklabelaxisrel#1#2#3{% \pgfplotsqpointoutsideofaxisrel{\csname pgfplots@#1ticklabelaxisspec\endcsname}{#2}{#3}% }% \def\pgfplotsqpointoutsideofticklabelaxistransformed#1#2#3{% \pgfplotsqpointoutsideofaxistransformed{\csname pgfplots@#1ticklabelaxisspec\endcsname}{#2}{#3}% }% % Expands to the three-character-identification for the axis % containing tick labels for axis #1. % % #1: either x, y or z. \def\pgfplotsticklabelaxisspec#1{\csname pgfplots@#1ticklabelaxisspec\endcsname}% % The unit outer normal vector for axis #1. % #1: one of x, y or z. \def\pgfplotspointouternormalvectorofticklabelaxis#1{% \pgfplotspointouternormalvectorofaxis{\csname pgfplots@#1ticklabelaxisspec\endcsname}% } % Defines \tick by applying any necessary math to the (possibly % transformed) tick value #2. % % #1: axis (x or y) % #2: tick value. \def\pgfplots@show@ticklabel@#1#2{% \csname ifpgfplots@apply@datatrafo@#1\endcsname \csname pgfplots@inverse@datascaletrafo@#1\endcsname{#2}% \ifcase\csname pgfplots@scaled@ticks@#1@choice\endcsname \or \expandafter\pgfmathfloatshift@\expandafter{\pgfmathresult}{\csname pgfplots@tick@scale@#1\endcsname}% \or \expandafter\pgfmathfloatshift@\expandafter{\pgfmathresult}{\csname pgfplots@tick@scale@#1\endcsname}% \or \expandafter\pgfmathfloatdivide@\expandafter{\pgfmathresult}{\csname pgfplots@tick@scale@#1\endcsname}% \or % scaled #1 ticks=manual. Invoke manual tick scaling code: \expandafter\let\expandafter\pgfplots@loc@TMPa\csname pgfplots@tick@scale@#1\endcsname \expandafter\pgfplots@loc@TMPa\expandafter{\pgfmathresult}% \fi % .. and this here provides \tick as fixed point repr: \expandafter\pgfmathfloattofixed\expandafter{\pgfmathresult}% \let\tick=\pgfmathresult \else \edef\tick{#2}% \pgfplots@if{pgfplots@#1islinear}{% \ifnum\csname pgfplots@scaled@ticks@#1@choice\endcsname=0 \else \pgfmathfloatparsenumber{#2}% \ifnum\csname pgfplots@scaled@ticks@#1@choice\endcsname=3 \expandafter\pgfmathfloatdivide@\expandafter{\pgfmathresult}{\csname pgfplots@tick@scale@#1\endcsname}% \else \expandafter\pgfmathfloatshift@\expandafter{\pgfmathresult}{\csname pgfplots@tick@scale@#1\endcsname}% \fi \expandafter\pgfmathfloattofixed\expandafter{\pgfmathresult}% \let\tick=\pgfmathresult \fi }{}% \fi \pgfkeysgetvalue{/pgfplots/#1 coord inv trafo/.@cmd}\pgfplots@loc@TMPa \ifx\pgfplots@loc@TMPa\pgfplots@empty@command@key \else \let\pgfmathresult=\tick% \expandafter\pgfplots@loc@TMPa\expandafter{\tick}\pgfeov \let\tick=\pgfmathresult \fi }% \def\pgfplots@user@ticklabel@list@x{% \pgfplotslistselectorempty\ticknum\of\pgfplots@xticklabels\to\tick \tick } \def\pgfplots@user@ticklabel@list@y{% \pgfplotslistselectorempty\ticknum\of\pgfplots@yticklabels\to\tick \tick } \def\pgfplots@user@ticklabel@list@z{% \pgfplotslistselectorempty\ticknum\of\pgfplots@zticklabels\to\tick \tick } \def\pgfplots@user@extra@ticklabel@list@x{% \pgfplotslistselectorempty\ticknum\of\pgfplots@extra@xticklabels\to\tick \tick } \def\pgfplots@user@extra@ticklabel@list@y{% \pgfplotslistselectorempty\ticknum\of\pgfplots@extra@yticklabels\to\tick \tick } \def\pgfplots@user@extra@ticklabel@list@z{% \pgfplotslistselectorempty\ticknum\of\pgfplots@extra@zticklabels\to\tick \tick } % Check if a label does not cross the x-axis \def\pgfplots@ytick@check@tickshow{% \pgfplots@tickshowtrue \if\pgfplots@yaxislinesnum2% center \ifcase\pgfplots@xaxislinesnum\relax \pgfplotsmath@ifapproxequal@dim {\pgfplots@tmpa}{\pgfplots@ymin@reg} {\pgfplots@loc@tick@placement@tolerance} {% \pgfplots@tickshowfalse }{}% \pgfplotsmath@ifapproxequal@dim {\pgfplots@tmpa}{\pgfplots@ymax@reg} {\pgfplots@loc@tick@placement@tolerance} {% \pgfplots@tickshowfalse }{}% \or \pgfplotsmath@ifapproxequal@dim {\pgfplots@tmpa}{\pgfplots@ymin@reg} {\pgfplots@loc@tick@placement@tolerance} {% \pgfplots@tickshowfalse }{% }% \or \pgfplotsmath@ifapproxequal@dim {\pgfplots@tmpa}{\pgfplots@logical@ZERO@y pt} {\pgfplots@loc@tick@placement@tolerance} {% \pgfplots@tickshowfalse }{}% \or \pgfplotsmath@ifapproxequal@dim {\pgfplots@tmpa}{\pgfplots@ymax@reg} {\pgfplots@loc@tick@placement@tolerance} {% \pgfplots@tickshowfalse }{}% \fi \fi } \def\pgfplots@ztick@check@tickshow{% \pgfplots@tickshowtrue \if\pgfplots@zaxislinesnum2% center \pgfplotsmath@ifapproxequal@dim {\pgfplots@tmpa}{\pgfplots@logical@ZERO@z pt} {\pgfplots@loc@tick@placement@tolerance} {% \pgfplots@tickshowfalse }{}% \fi }% % Fills the macros % \pgfplots@tick@beg@a \pgfplots@tick@end@a % \pgfplots@tick@beg@b \pgfplots@tick@end@b % with coordinates such that % (\pgfplots@tick@beg@a,\pgfplots@tmpa) -- (\pgfplots@tick@end@a,\pgfplots@tmpa) % produces a correct tick line. % % The '@b' variant is only used in case of \pgfplots@ytickposnum = 0 % % #1 : the current axis (x or y). % #2 : the current tick width % \def\pgfplots@prepare@tick@offsets@for@#1#2{% % FIXME : this stuff was ok for 2D. % For 3D, it works only for the cases of boxed axes or centered % axis lines. \ifcase\csname pgfplots@#1tickposnum\endcsname\relax % both %(\pgfplots@xcoordminTEX-\pgfplots@tick@offset, \pgfplots@tmpa) -- ++( #2, 0pt) \edef\pgfplots@tick@beg@a{\csname pgfplots@\pgfplotspointonorientedsurfaceB min\endcsname}% \pgfmathsubtract@{\pgfplots@tick@beg@a}{\pgfplots@tick@offset}% \let\pgfplots@tick@beg@a=\pgfmathresult \pgfmathadd@{\pgfplots@tick@beg@a}{#2}% \let\pgfplots@tick@end@a=\pgfmathresult % %(\pgfplots@xcoordmaxTEX+\pgfplots@tick@offset, \pgfplots@tmpa) -- ++(-#2, 0pt) \edef\pgfplots@tick@beg@b{\csname pgfplots@\pgfplotspointonorientedsurfaceB max\endcsname}% \pgfmathadd@{\pgfplots@tick@beg@b}{\pgfplots@tick@offset}% \let\pgfplots@tick@beg@b=\pgfmathresult \pgfmathsubtract@{\pgfplots@tick@beg@b}{#2}% \let\pgfplots@tick@end@b=\pgfmathresult% \or % left % (\pgfplots@xcoordminTEX-\pgfplots@tick@offset, \pgfplots@tmpa) -- ++( #2, 0pt); \edef\pgfplots@tick@beg@a{\csname pgfplots@\pgfplotspointonorientedsurfaceB min\endcsname}% \pgfmathsubtract@{\pgfplots@tick@beg@a}{\pgfplots@tick@offset}% \let\pgfplots@tick@beg@a=\pgfmathresult \pgfmathadd@{\pgfplots@tick@beg@a}{#2}% \let\pgfplots@tick@end@a=\pgfmathresult \or % center % (\pgfplots@ZERO@x -\pgfplots@tick@offset, \pgfplots@tmpa) -- ++( #2, 0pt); \pgfmathsubtract@{\csname pgfplots@logical@ZERO@\pgfplotspointonorientedsurfaceB \endcsname}{\pgfplots@tick@offset}% \let\pgfplots@tick@beg@a=\pgfmathresult \pgfmathadd@{\pgfplots@tick@beg@a}{#2}% \let\pgfplots@tick@end@a=\pgfmathresult% \or % right % (\pgfplots@xcoordmaxTEX+\pgfplots@tick@offset, \pgfplots@tmpa) -- ++(-#2, 0pt); \edef\pgfplots@tick@beg@b{\csname pgfplots@\pgfplotspointonorientedsurfaceB max\endcsname}% \pgfmathadd@{\pgfplots@tick@beg@b}{\pgfplots@tick@offset}% \let\pgfplots@tick@beg@b=\pgfmathresult \pgfmathsubtract@{\pgfplots@tick@beg@b}{#2}% \let\pgfplots@tick@end@b=\pgfmathresult% \else % FALL BACK. never used, I guess? % (\pgfplots@xcoordminTEX-\pgfplots@tick@offset, \pgfplots@tmpa) -- ++( #2, 0pt); \edef\pgfplots@tick@beg@a{\csname pgfplots@\pgfplotspointonorientedsurfaceB min\endcsname}% \pgfmathsubtract@{\pgfplots@tick@beg@a}{\pgfplots@tick@offset}% \let\pgfplots@tick@beg@a=\pgfmathresult \pgfmathadd@{\pgfplots@tick@beg@a}{#2}% \let\pgfplots@tick@end@a=\pgfmathresult \fi }% \newif\ifpgfplots@needsminorloop \def\pgfplots@draw@tick@scale@label@for#1{% \csname ifpgfplots@#1islinear\endcsname \begingroup \def\pgfplots@temp@isbaseten{0}% \ifcase\csname pgfplots@scaled@ticks@#1@choice\endcsname \global\let\pgfplots@glob@TMPa=\pgfutil@empty \or \xdef\pgfplots@glob@TMPa{\csname pgfplots@tick@scale@#1\endcsname}% \def\pgfplots@temp@isbaseten{1}% \or \xdef\pgfplots@glob@TMPa{\csname pgfplots@tick@scale@#1\endcsname}% \def\pgfplots@temp@isbaseten{1}% \or \xdef\pgfplots@glob@TMPa{\csname pgfplots@tick@scale@#1\endcsname}% % real: \or % manual: \global\def\pgfplots@glob@TMPa{dummyargument}% \fi \if1\pgfplots@temp@isbaseten \expandafter\c@pgf@counta\pgfplots@glob@TMPa\relax \multiply\c@pgf@counta by-1 \ifnum\c@pgf@counta=0\relax \global\let\pgfplots@glob@TMPa=\pgfutil@empty \else \xdef\pgfplots@glob@TMPa{\the\c@pgf@counta}% \fi \fi \endgroup \ifx\pgfplots@glob@TMPa\pgfutil@empty \else \begingroup \pgfkeysgetvalue{/pgfplots/#1tick scale label code/.@cmd}\pgfplots@loc@TMPa \ifx\pgfplots@loc@TMPa\pgfplots@empty@command@key \else \edef\pgfplots@tick@scale@labels{\noexpand\pgfplots@invoke@pgfkeyscode{/pgfplots/#1tick scale label code/.@cmd}{\pgfplots@glob@TMPa}}% % \pgfplots@change@pgfpoints@to@descriptioncs % \node[% /pgfplots/every tick label,% /pgfplots/every #1 tick label,% /pgfplots/every #1 tick scale label] {\pgfplots@tick@scale@labels}; \fi \endgroup \fi \fi } % Check if the current tick position, stored in \pgfplots@tmpa, % does not cross the y-axis. % % This is just a special case for centered axis lines. \def\pgfplots@xtick@check@tickshow{% \pgfplots@tickshowtrue \if\pgfplots@xaxislinesnum2% center \ifcase\pgfplots@yaxislinesnum\relax \pgfplotsmath@ifapproxequal@dim {\pgfplots@tmpa}{\pgfplots@xmin@reg} {\pgfplots@loc@tick@placement@tolerance} {% \pgfplots@tickshowfalse }{}% \pgfplotsmath@ifapproxequal@dim {\pgfplots@tmpa}{\pgfplots@xmax@reg} {\pgfplots@loc@tick@placement@tolerance} {% \pgfplots@tickshowfalse }{}% \or \pgfplotsmath@ifapproxequal@dim {\pgfplots@tmpa}{\pgfplots@xmin@reg} {\pgfplots@loc@tick@placement@tolerance} {% \pgfplots@tickshowfalse }{}% \or \pgfplotsmath@ifapproxequal@dim {\pgfplots@tmpa}{\pgfplots@logical@ZERO@x pt} {\pgfplots@loc@tick@placement@tolerance} {% \pgfplots@tickshowfalse }{}% \or \pgfplotsmath@ifapproxequal@dim {\pgfplots@tmpa}{\pgfplots@xmax@reg} {\pgfplots@loc@tick@placement@tolerance} {% \pgfplots@tickshowfalse }{}% \fi \fi } % Draws extra ticks including grid lines, tick lines and tick labels % along the current oriented surface. % % See \pgfplots@drawticklines@onorientedsurf@ for a description of the % oriented surface. % % #1 : tick position list \def\pgfplots@draw@extra@ticks@onorientedsurf{% \expandafter\pgfplots@draw@extra@ticks@onorientedsurf@\pgfplotspointonorientedsurfaceA }% % #1: axis (x or y) % #2: tick position list \def\pgfplots@draw@extra@ticks@onorientedsurf@#1#2{% \begingroup \def\pgfplots@scaled@ticks@x@choice{0}% \def\pgfplots@scaled@ticks@y@choice{0}% \def\pgfplots@scaled@ticks@z@choice{0}% \csname pgfplots@#1minorticksfalse\endcsname \csname pgfplots@#1minorgridsfalse\endcsname \expandafter\let\expandafter\axis@TMP\csname pgfplots@extra@#1ticklabel\endcsname \expandafter\let\csname pgfplots@#1ticklabel\endcsname=\axis@TMP % \pgfplotsset{/pgfplots/every extra #1 tick}% % use a scope here such that line width and draw color can be set. \scope[/pgfplots/.cd,/pgfplots/every extra #1 tick] \pgfplots@prepare@tick@coordlists@for{#1}{#2}% \pgfplots@drawgridlines@onorientedsurf% \pgfplots@drawticklines@onorientedsurf% \pgfplots@drawticklabels@onorientedsurf% \endscope \endgroup } % Computes final major and minor tick positions into global lists % \pgfplots@prepared@tick@positions@major@x % and % \pgfplots@prepared@tick@positions@minor@x. % % The major tick list contains tuples (canvas position,logical position) % while the minor tick list contains just the canvas position. % % #1: the axis % #2: the tick list. % % PRECONDITION: % - \pgfplots@determinedefaultvalues has been executed. % That means particularly that \pgfplots@[xy][min,max] are available in TeX point % range (after datascaling and logs). % POSTCONDITION: % - the lists % \pgfplots@prepared@tick@positions@major@x % \pgfplots@prepared@tick@positions@major@tickindices@x % \pgfplots@prepared@tick@positions@minor@x % are ready. \def\pgfplots@prepare@tick@coordlists@for#1#2{% \begingroup \expandafter\let\expandafter\ifpgfplots@islinear\csname ifpgfplots@#1islinear\endcsname \expandafter\let\expandafter\ifpgfplots@minorticks\csname ifpgfplots@#1minorticks\endcsname \expandafter\let\expandafter\ifpgfplots@minorgrids\csname ifpgfplots@#1minorgrids\endcsname % these lists need to be global such that I can fill them inside % of \foreach statements. And, yes: I have also added a TeX group % on my own (but that's not the problem). \global\pgfplotslistnewempty\pgfplots@prepared@tick@positions@major \global\pgfplotslistnewempty\pgfplots@prepared@tick@positions@major@tickindices \global\pgfplotslistnewempty\pgfplots@prepared@tick@positions@minor % \afterassignment\pgfplots@gobble@until@relax \pgfplots@tmpa=\pgfkeysvalueof{/pgfplots/#1tick placement tolerance}pt\relax \pgfplots@tmpa=\csname pgfplots@#1@inverseveclength\endcsname\pgfplots@tmpa \edef\pgfplots@loc@tick@placement@tolerance{\the\pgfplots@tmpa}% % \advance\csname pgfplots@#1min@reg\endcsname by-\pgfplots@tmpa \advance\csname pgfplots@#1max@reg\endcsname by\pgfplots@tmpa % \edef\pgfplots@loc@TMPa{#2}% \ifx\pgfplots@loc@TMPa\pgfutil@empty \else \ifpgfplots@minorticks \pgfplots@needsminorlooptrue \else \ifpgfplots@minorgrids \pgfplots@needsminorlooptrue \else \pgfplots@needsminorloopfalse \fi \fi \ifpgfplots@needsminorloop \ifpgfplots@islinear \expandafter\let\expandafter\pgfplots@minor@tick@num\csname pgfplots@minor@#1tick@num\endcsname \begingroup \c@pgf@counta=\pgfplots@minor@tick@num\relax \advance\c@pgf@counta by1\relax \pgfplots@tmpa=\csname pgfplots@tick@distance@#1\endcsname pt % \divide\pgfplots@tmpa by\c@pgf@counta \edef\pgfmathresult{\pgf@sys@tonumber{\pgfplots@tmpa}}% \pgfmath@smuggleone\pgfmathresult \endgroup \let\pgfplots@minor@tick@dist=\pgfmathresult \else \def\pgfplots@minor@tick@num{9}% \fi \fi % % Prepare the [xy]tick[min|max] key processing: \let\pgfplots@checktickminmax=\pgfutil@empty \expandafter\ifx\csname pgfplots@#1tickmin\endcsname\pgfutil@empty \else \expandafter\def\expandafter\pgfplots@checktickminmax\expandafter{% \pgfplots@checktickminmax \ifdim\pgfplots@tmpa<\csname pgfplots@#1tickmin\endcsname pt \pgfplots@tickshowfalse \fi }% \fi \expandafter\ifx\csname pgfplots@#1tickmax\endcsname\pgfutil@empty \else \expandafter\def\expandafter\pgfplots@checktickminmax\expandafter{% \pgfplots@checktickminmax \ifdim\pgfplots@tmpa>\csname pgfplots@#1tickmax\endcsname pt \pgfplots@tickshowfalse \fi }% \fi % % \gdef\pgfplots@glob@TMPa{0}% \foreach \x in {#2} {% \let\pgfplots@ticknum=\pgfplots@glob@TMPa % \pgfplots@tmpa=\x pt % \csname pgfplots@#1tick@check@tickshow\endcsname \pgfplots@checktickminmax % \ifpgfplots@tickshow \ifdim\pgfplots@tmpa<\csname pgfplots@#1min@reg\endcsname \else \ifdim\pgfplots@tmpa>\csname pgfplots@#1max@reg\endcsname \else \expandafter\pgfplotslistpushbackglobal\x\to\pgfplots@prepared@tick@positions@major \expandafter\pgfplotslistpushbackglobal\pgfplots@ticknum\to\pgfplots@prepared@tick@positions@major@tickindices \fi \fi \fi % X-Axis ticks bottom and top % in log: % log( i*10^k ) = log\pgfplots@i + k\log10 -> draw ticks for i=1..9 \ifpgfplots@needsminorloop \foreach \pgfplots@i in {1,...,\pgfplots@minor@tick@num} {% \begingroup \ifpgfplots@islinear \pgfplots@tmpa=\pgfplots@minor@tick@dist pt % \pgfplots@tmpa=\pgfplots@i\pgfplots@tmpa \else \pgfplots@tmpa=\csname pgfplotsmathlogi@#1\endcsname\pgfplots@i pt % \fi \edef\pgfmathresult{\the\pgfplots@tmpa}% \pgfmath@smuggleone\pgfmathresult \endgroup \advance\pgfplots@tmpa by\pgfmathresult\relax \pgfplots@tickshowtrue \pgfplots@checktickminmax \ifpgfplots@tickshow \ifdim\pgfplots@tmpa<\csname pgfplots@#1min@reg\endcsname \else \ifdim\pgfplots@tmpa>\csname pgfplots@#1max@reg\endcsname \else \edef\pgfmathresult{\pgf@sys@tonumber{\pgfplots@tmpa}}% \expandafter\pgfplotslistpushbackglobal\pgfmathresult\to\pgfplots@prepared@tick@positions@minor \fi \fi \fi }% \fi \pgfplotsutil@advancestringcounter\pgfplots@ticknum % carry \ticknum outside of this scope: \global\let\pgfplots@glob@TMPa=\pgfplots@ticknum }% \fi \endgroup \expandafter\let\csname pgfplots@prepared@tick@positions@minor@#1\endcsname=\pgfplots@prepared@tick@positions@minor \expandafter\let\csname pgfplots@prepared@tick@positions@major@#1\endcsname=\pgfplots@prepared@tick@positions@major \expandafter\let\csname pgfplots@prepared@tick@positions@major@tickindices@#1\endcsname=\pgfplots@prepared@tick@positions@major@tickindices \global\let\pgfplots@prepared@tick@positions@major=\relax \global\let\pgfplots@prepared@tick@positions@major@tickindices=\relax \global\let\pgfplots@prepared@tick@positions@minor=\relax }% % Draws grid lines at the a-positions of the currently set oriented % surface. % % Tick positions are taken out of the already precomputed list % \pgfplots@prepared@tick@positions@major@... % % See \pgfplots@drawticklines@onorientedsurf@ for a description of the % oriented surface. % % #1 : the verbatim axis name (either 'x' or 'y') % #2 : the index of the axis (either 0 or 1) \def\pgfplots@drawgridlines@onorientedsurf{% \expandafter\pgfplots@drawgridlines@onorientedsurf@\pgfplotspointonorientedsurfaceA }% \def\pgfplots@drawgridlines@onorientedsurf@#1{% \pgfplots@if{pgfplots@shownothingof@\pgfplotspointonorientedsurfaceB}{% \relax }{% \begingroup \pgfplots@ifgridlines@onorientedsurf@should@be@drawn{% \expandafter\let\expandafter\pgfplots@prepared@tick@positions@major@\csname pgfplots@prepared@tick@positions@major@#1\endcsname \expandafter\let\expandafter\pgfplots@prepared@tick@positions@minor@\csname pgfplots@prepared@tick@positions@minor@#1\endcsname \pgfplots@loop@CONTINUEfalse \pgfplots@if{pgfplots@#1majorgrids}{\pgfplots@loop@CONTINUEtrue}{}% \pgfplots@if{pgfplots@#1minorgrids}{\pgfplots@loop@CONTINUEtrue}{}% \ifpgfplots@loop@CONTINUE \scope \pgfplots@drawtickgridlines@INSTALLCLIP@onorientedsurf#1 % \pgfplots@if{pgfplots@#1minorgrids}{% \draw[% /pgfplots/every axis grid, /pgfplots/every minor grid, /pgfplots/every axis #1 grid, /pgfplots/every minor #1 grid]% \pgfextra \pgfplotslistforeach\pgfplots@prepared@tick@positions@minor@\as\pgfplots@curgridpos{% \pgfpathmoveto{\pgfplotspointonorientedsurfaceab{\pgfplots@curgridpos}{\csname pgfplots@\pgfplotspointonorientedsurfaceB min\endcsname}}% \pgfpathlineto{\pgfplotspointonorientedsurfaceab{\pgfplots@curgridpos}{\csname pgfplots@\pgfplotspointonorientedsurfaceB max\endcsname}}% }% \endpgfextra; }{}% % \pgfplots@if{pgfplots@#1majorgrids}{% \draw[% /pgfplots/every axis grid, /pgfplots/every major grid, /pgfplots/every axis #1 grid, /pgfplots/every major #1 grid]% \pgfextra \pgfplotslistforeach\pgfplots@prepared@tick@positions@major@\as\pgfplots@curgridpos{% \pgfpathmoveto{\pgfplotspointonorientedsurfaceab{\pgfplots@curgridpos}{\csname pgfplots@\pgfplotspointonorientedsurfaceB min\endcsname}}% \pgfpathlineto{\pgfplotspointonorientedsurfaceab{\pgfplots@curgridpos}{\csname pgfplots@\pgfplotspointonorientedsurfaceB max\endcsname}}% }% \endpgfextra; }{}% % \endscope \fi }{}% \endgroup }% } % Draws ticks on the currently active "oriented surface". % % The oriented surface is two dimensional and has been initialised % with \pgfplotspointonorientedsurfaceabsetupfor*** somehow. % % The idea is now the following: % - the tick positions change along the FIRST coordinate of this % surface: % % x ---- x ---- x ---- x % --> FIRST --> % % - the tick lines are drawn along the SECOND coordinate of this % surface: % % | ---- | ---- | ---- | | SECOND % | | | | v % % for example, % \pgfplotspointonorientedsurfaceab@setupfor@xyZ{1} % \pgfplots@drawticklines@onorientedsurf % will draw ticks at x-positions designated by \pgfplots@xtick. The % small tick lines will be drawn along the y axis. For each processed % point, the z coordinate will be fixed to '1'. % % Another example: % \pgfplotspointonorientedsurfaceab@setupfor@yxZ{-1} % \pgfplots@drawticklines@onorientedsurf % will draw ticks at y-positions designated by \pgfplots@ytick. The % small tick lines will be drawn along the x axis. For each processed % point, the z coordinate will be fixed to '-1'. % % Tick positions are taken out of the already precomputed list % \pgfplots@prepared@tick@positions@major@... \def\pgfplots@drawticklines@onorientedsurf{% \expandafter\pgfplots@drawticklines@onorientedsurf@\pgfplotspointonorientedsurfaceA }% % Avoids tick lines which are too thick by introducing a clipping % region. Tick lines (and grid lines) won't extend to the left or % right of axis #1. \def\pgfplots@drawtickgridlines@INSTALLCLIP@onorientedsurf#1{% \pgfinterruptboundingbox% \begingroup \pgf@xa=5cm \edef\pgfplots@loc@TMPc{\pgf@sys@tonumber{\pgf@xa}}% % the case ||e_b|| == 0 should never happen here! Should be % caught before entering this routine. \pgfmathmultiply@{\pgfplots@loc@TMPc}{\csname pgfplots@\pgfplotspointonorientedsurfaceB @inverseveclength\endcsname}% \let\pgfplots@loc@LENGTH=\pgfmathresult \pgfmathsubtract@{\csname pgfplots@\pgfplotspointonorientedsurfaceB min\endcsname}{\pgfplots@loc@LENGTH}% \let\pgfplots@loc@MIN=\pgfmathresult \pgfmathadd@{\csname pgfplots@\pgfplotspointonorientedsurfaceB max\endcsname}{\pgfplots@loc@LENGTH}% \let\pgfplots@loc@MAX=\pgfmathresult \pgfpathmoveto{\pgfplotspointonorientedsurfaceab{\csname pgfplots@#1min\endcsname}{\pgfplots@loc@MIN}}% \pgfpathlineto{\pgfplotspointonorientedsurfaceab{\csname pgfplots@#1max\endcsname}{\pgfplots@loc@MIN}}% \pgfpathlineto{\pgfplotspointonorientedsurfaceab{\csname pgfplots@#1max\endcsname}{\pgfplots@loc@MAX}}% \pgfpathlineto{\pgfplotspointonorientedsurfaceab{\csname pgfplots@#1min\endcsname}{\pgfplots@loc@MAX}}% \pgfusepath{clip}% \endgroup \endpgfinterruptboundingbox% }% \def\pgfplots@drawticklines@onorientedsurf@#1{% \pgfplots@if{pgfplots@shownothingof@\pgfplotspointonorientedsurfaceB}{% \relax }{% \scope \pgfplots@ifaxisline@B@onorientedsurf@should@be@drawn{0}{% \def\pgfplots@drawticklines@for@placecomputedtick@LOWEROK{1}% }{% \def\pgfplots@drawticklines@for@placecomputedtick@LOWEROK{0}% }% \pgfplots@ifaxisline@B@onorientedsurf@should@be@drawn{1}{% \def\pgfplots@drawticklines@for@placecomputedtick@UPPEROK{1}% }{% \def\pgfplots@drawticklines@for@placecomputedtick@UPPEROK{0}% }% \if\pgfkeysvalueof{/pgfplots/\pgfplotspointonorientedsurfaceB\space dir/value}r% % local special handling for reversed axes: exchange % meaning of 'left' and 'right' here. % % the rest of the pgfplots code does that automatically because % there, tickposnum is relevant to determine the axes % which contains tick labels. And this algorithm checks % for reversed axes implicitly. % \if1\csname pgfplots@\pgfplotspointonorientedsurfaceA tickposnum\endcsname \expandafter\def\csname pgfplots@\pgfplotspointonorientedsurfaceA tickposnum\endcsname{3}% \else \if3\csname pgfplots@\pgfplotspointonorientedsurfaceA tickposnum\endcsname \expandafter\def\csname pgfplots@\pgfplotspointonorientedsurfaceA tickposnum\endcsname{1}% \fi \fi \fi \ifcase\csname pgfplots@\pgfplotspointonorientedsurfaceA tickposnum\endcsname\relax % both \or % lower \def\pgfplots@drawticklines@for@placecomputedtick@UPPEROK{0}% \or % center \def\pgfplots@drawticklines@for@placecomputedtick@UPPEROK{0}% \or % upper \def\pgfplots@drawticklines@for@placecomputedtick@LOWEROK{0}% \else % never used? \def\pgfplots@drawticklines@for@placecomputedtick@UPPEROK{0}% \fi \begingroup % Assemble the \pgfplots@drawticklines@for@placecomputedtick % command. \let\E=\noexpand \xdef\pgfplots@drawticklines@for@placecomputedtick{% \if\pgfplots@drawticklines@for@placecomputedtick@LOWEROK1% \E\pgfpathmoveto{\E\pgfplotspointonorientedsurfaceab{\E\pgfplots@curtickpos}{\E\pgfplots@tick@beg@a}}% \E\pgfpathlineto{\E\pgfplotspointonorientedsurfaceab{\E\pgfplots@curtickpos}{\E\pgfplots@tick@end@a}}% \fi \if\pgfplots@drawticklines@for@placecomputedtick@UPPEROK1% \E\pgfpathmoveto{\E\pgfplotspointonorientedsurfaceab{\E\pgfplots@curtickpos}{\E\pgfplots@tick@beg@b}}% \E\pgfpathlineto{\E\pgfplotspointonorientedsurfaceab{\E\pgfplots@curtickpos}{\E\pgfplots@tick@end@b}}% \fi }% \endgroup \expandafter\let\expandafter\pgfplots@prepared@tick@positions@major@\csname pgfplots@prepared@tick@positions@major@#1\endcsname \expandafter\let\expandafter\pgfplots@prepared@tick@positions@minor@\csname pgfplots@prepared@tick@positions@minor@#1\endcsname \pgfplots@drawtickgridlines@INSTALLCLIP@onorientedsurf#1 % \pgfplots@if{pgfplots@#1minorticks}{% \draw[% /pgfplots/every tick, /pgfplots/every minor tick, /pgfplots/every #1 tick, /pgfplots/every minor #1 tick]% \pgfextra \pgfmathparse{\pgfplots@subtickwidth}% \let\pgfplots@subtickwidth@=\pgfmathresult \pgfmathmultiply@{\pgfplots@subtickwidth@}{\csname pgfplots@\pgfplotspointonorientedsurfaceB @inverseveclength\endcsname}% \let\pgfplots@subtickwidth@=\pgfmathresult \let\pgfplots@subtickwidth=\pgfmathresult \ifcase\csname pgfplots@#1tickalignnum\endcsname\relax \def\pgfplots@tick@offset{0}% \or \let\pgfplots@tick@offset=\pgfplots@subtickwidth@% \or \pgfmathmultiply@{0.5}{\pgfplots@subtickwidth@}% \let\pgfplots@tick@offset=\pgfmathresult% \fi \pgfplots@prepare@tick@offsets@for@{#1}{\pgfplots@subtickwidth@}% \pgfplotslistforeach\pgfplots@prepared@tick@positions@minor@\as\pgfplots@curtickpos{% \pgfplots@drawticklines@for@placecomputedtick }% \endpgfextra; }{}% % \pgfplots@if{pgfplots@#1majorticks}{% \draw[% /pgfplots/every tick, /pgfplots/every major tick, /pgfplots/every #1 tick, /pgfplots/every major #1 tick]% \pgfextra \pgfmathparse{\pgfplots@tickwidth}% \let\pgfplots@tickwidth@=\pgfmathresult \pgfmathmultiply@{\pgfplots@tickwidth@}{\csname pgfplots@\pgfplotspointonorientedsurfaceB @inverseveclength\endcsname}% \let\pgfplots@tickwidth@=\pgfmathresult \let\pgfplots@tickwidth=\pgfmathresult \ifcase\csname pgfplots@#1tickalignnum\endcsname\relax \def\pgfplots@tick@offset{0}% \or \let\pgfplots@tick@offset=\pgfplots@tickwidth@% \or \pgfmathmultiply@{0.5}{\pgfplots@tickwidth@}% \let\pgfplots@tick@offset=\pgfmathresult% \fi \pgfplots@prepare@tick@offsets@for@{#1}{\pgfplots@tickwidth@}% \pgfplotslistforeach\pgfplots@prepared@tick@positions@major@\as\pgfplots@curtickpos{% \pgfplots@drawticklines@for@placecomputedtick }% \endpgfextra; }{}% % \endscope }% } % Draws tick labels at the positions of the currently set oriented % surface. % % Tick positions are taken out of the already precomputed list % \pgfplots@prepared@tick@positions@major@... % % For 2D axes, this task is relatively simple: % we iterate through every prepared major tick position and place a % tick label. Open points, however, are the question whether to use % the RIGHT or the LEFT axis line on the current oriented surface: % % direction 'b' (second oriented) % |-------------------------| % | | % | | % | |direction 'a' (first oriented) % | | % | | % | | % |-------------------------| % Left Right % % Given the axis line which shall contain the labels, we have to % decide how to align the tick label nodes: on the left or on the % right? Of course, we want to align them such that they are "outside" % of the figure! That's simple as well: "Left axis line => outside % means left", "Right axis line => outside means right". % % That's all, basically. % % For 3D axes, all these points are basically ... the same! % Now it can happen that the current oriented surface shall % not contain ANY tick label. In that case, we do nothing. % Furthermore, the "outside" direction (i.e. the anchoring of the % label nodes) is a little bit more difficult. % % % See \pgfplots@drawticklines@onorientedsurf@ for a description of the % oriented surface. \def\pgfplots@drawticklabels@onorientedsurf{% \expandafter\pgfplots@drawticklabels@onorientedsurf@\pgfplotspointonorientedsurfaceA } \def\pgfplots@drawticklabels@onorientedsurf@#1{% \begingroup \expandafter\let\expandafter\pgfplots@prepared@tick@positions@major@\csname pgfplots@prepared@tick@positions@major@#1\endcsname % check whether % - we need to place tick labels on the LEFT side, % - we need to place tick labels on the RIGHT side, % - we don't need tick labels for the current surface at all: \pgfplotspointonorientedsurfaceabmatchaxisline{\csname pgfplots@#1ticklabelaxisspec\endcsname}{\pgfplots@ticklabelside}% \ifx\pgfplots@ticklabelside\pgfutil@empty % SKIP. The current oriented surface shall not get tick labels % for #1. \else \pgfplots@if{pgfplots@#1majorticks}{% \pgfplots@if{pgfplots@#1islinear}{% \pgfplots@init@scaled@tick@for{#1}% }{\relax}% \begingroup \pgfkeysalso{/tikz/every node/.append style={/pgfplots/every tick label,/pgfplots/every #1 tick label}}% \pgfplots@drawticklabels@onorientedsurf@prepareanchor#1% % \pgfplotsmath@ifzero{\csname pgfplots@\pgfplotspointonorientedsurfaceB @veclength\endcsname}{% \def\pgfplots@tick@offset{0}% }{% \ifcase\csname pgfplots@#1tickalignnum\endcsname\relax \def\pgfmathresult{0}% \or \pgfmathparse{\pgfplots@tickwidth}% \or \pgfmathmultiply{0.5}{\pgfplots@tickwidth}% \fi \let\pgfplots@tick@offset=\pgfmathresult \pgfplots@ticklabel@maxtickdimen@extrashift{#1}{\pgfplots@tick@offset}% \pgfmathmultiply@{\pgfplots@tick@offset}{\csname pgfplots@\pgfplotspointonorientedsurfaceB @inverseveclength\endcsname}% \let\pgfplots@tick@offset=\pgfmathresult }% % \if2\csname pgfplots@#1axislinesnum\endcsname % Centered axis lines? \expandafter\let\expandafter\pgfplots@tick@origin\csname pgfplots@logical@ZERO@\pgfplotspointonorientedsurfaceB\endcsname% % FIXME : that stuff here does not respect % '[xyz]tickpos num' keys! \pgfplots@tickposchoiceb \if r\pgfkeysvalueof{/pgfplots/\pgfplotspointonorientedsurfaceB\space dir/value}% % special handling for reversed axes. \pgfmathmultiply{-1}{\pgfplots@tick@offset}% \let\pgfplots@tick@offset=\pgfmathresult \fi \pgfmathsubtract@{\pgfplots@tick@origin}{\pgfplots@tick@offset}% \else \if0\pgfplots@ticklabelside \expandafter\let\expandafter\pgfplots@tick@origin\csname pgfplots@\pgfplotspointonorientedsurfaceB min\endcsname% \pgfplots@tickposchoiceb \pgfmathsubtract@{\pgfplots@tick@origin}{\pgfplots@tick@offset}% \else \if1\pgfplots@ticklabelside \expandafter\let\expandafter\pgfplots@tick@origin\csname pgfplots@\pgfplotspointonorientedsurfaceB max\endcsname% \pgfplots@tickposchoicea \pgfmathadd@{\pgfplots@tick@origin}{\pgfplots@tick@offset}% \else % Should never happen. \pgfplots@error{Internal logic error during tick label placement (got placement character '\pgfplots@ticklabelside'). Please report this as a bug or verify your input arguments to #1ticklabel pos.}% \expandafter\let\expandafter\pgfplots@tick@origin\csname pgfplots@\pgfplotspointonorientedsurfaceB min\endcsname% \pgfplots@tickposchoiceb \pgfmathsubtract@{\pgfplots@tick@origin}{\pgfplots@tick@offset}% \fi \fi \fi % % make sure the \pgfmathlogtologten method works even for % non-standard 'log basis #1': \expandafter\let\expandafter\pgfmathlogtologten@\csname pgfplotsmathlogtologten@#1@\endcsname % \let\pgfplots@tick@origin=\pgfmathresult% \xdef\pgfplots@show@ticklabel@LASTTICK{}% \pgfplotslistforeachungrouped\pgfplots@prepared@tick@positions@major@\as\pgfplots@curtickpos{% \expandafter\pgfplotslistpopfront\csname pgfplots@prepared@tick@positions@major@tickindices@#1\endcsname\to\pgfplots@ticknum \pgfplots@show@ticklabel {#1}{\pgfplots@curtickpos}(\pgfplots@curtickpos,\pgfplots@tick@origin)% {\pgfplots@ticknum}% }% \pgfplots@ticklabel@maxtickdimen@finish{#1}% \endgroup \pgfplots@draw@tick@scale@label@for #1% }% {\relax}% if...@major==false \fi \endgroup } % This here does the main work for any tick label ANCHORING. % % FIXME : the new 'near ticklabel' anchors are now the default method % to place tick labels. % % This feature here can be used to disable this anchoring, i.e. set % 'ticklabel anchor=tikz' to use a stupid heuristics. % % There are actually two choices: % Choice 1: near ticklabel % This choice places tick labels fully automatic outside of the % figure, all on a line which is parallel to the axis which % contains the corresponding tick labels. % % Since we are currently working on a restricted surface, we have % three direction related to that surface: % 'a': this is the direction in which tick positions are known. % 'b': the 'orthogonal' axis to 'a' which is also in the surface. % 'n': the surface normal. % Now, the idea for tick labels is to place them at % SCALE_b * b + SCALE_n * n, % where the SCALE_[bn] numbers are choosen such that the label is % outside of the axis. % % The offset is simply added to the transformation matrix (as a % shift). % % Choice 2: tikz. % This is more or less a backwards compatibility feature. It does % not change the transformation matrix. It simply sets the 'at' key % of each node to the tick position and prepares the correct anchors % for the TikZ '\node' commands. % That's all here. % % PRECONDITION: % - called inside of \pgfplots@drawticklabels@onorientedsurf@ % POSTCONDITION: % - defines % - \pgfplots@tickposchoicea % if called, sets keys such that tick labels are RIGHT (TOP) of % the axis, % % - \pgfplots@tickposchoiceb % if called, sets keys such that tick labels are LEFT % (BOTTOM) of the axis, \def\pgfplots@drawticklabels@onorientedsurf@prepareanchor#1{% \if\csname pgfplots@ticklabel@anchor@#1\endcsname0% % auto is the same as 'near ticklabel': \expandafter\def\csname pgfplots@ticklabel@anchor@#1\endcsname{1}% \fi \ifcase\csname pgfplots@ticklabel@anchor@#1\endcsname% % 0: doesn't happen, see above. \or % 1: near ticklabel. % The following code contains automatically % aligned tick labels (especially for 3D axes). % see the manual for the |near ticklabel| anchors. \pgfkeys{/tikz/anchor=near #1ticklabel}% % % process the (optional) ticklabel distance: \begingroup \pgfkeysgetvalue{/pgfplots/#1ticklabel shift}\pgfmathresult \ifx\pgfmathresult\pgfutil@empty \else \afterassignment\pgfplots@gobble@until@relax \pgf@xa=\pgfkeysvalueof{/pgfplots/#1ticklabel shift}pt\relax \multiply\pgf@xa by-1 % the direction vector points to the INSIDE. the shift should have opposite sign. \edef\pgfmathresult{\pgf@sys@tonumber\pgf@xa}% \fi \pgfmath@smuggleone\pgfmathresult \endgroup \let\pgfplots@loc@TMPc=\pgfmathresult \ifx\pgfplots@loc@TMPc\pgfutil@empty \else \pgftransformshift{% \pgfplotspointouternormalvectorofticklabelaxis{#1}% \pgfqpointscale{-\pgfplots@loc@TMPc}{}% }% \fi % % these things are irrelevant here: \let\pgfplots@tickposchoicea=\pgfutil@empty \let\pgfplots@tickposchoiceb=\pgfutil@empty \or % 2: tikz. % We simply prepare the default anchor. % Actually, this code is just for backwards compatibility - % there may be people who prefer to set anchors. The % 'near ticklabel' implementation is much more general, however. \if\pgfplotspointonorientedsurfaceB x \def\pgfplots@tickposchoicea{\tikzset{right}}% \def\pgfplots@tickposchoiceb{\tikzset{left}}% \else \if\pgfplotspointonorientedsurfaceB y \def\pgfplots@tickposchoicea{\tikzset{above}}% \def\pgfplots@tickposchoiceb{\tikzset{below}}% \else \def\pgfplots@tickposchoicea{\tikzset{anchor=north east}}% \def\pgfplots@tickposchoiceb{\tikzset{anchor=south east}}% \fi \fi \fi \pgfplots@ticklabel@maxtickdimen@prepare@for@normalvec {#1}% {\pgfplotspointouternormalvectorofticklabelaxis{#1}}% }% \newif\ifpgfplots@checkuniform@isfirst % Checks whether the argument to xtick or ytick is a UNIFORM tick % sequence. % % A uniform tick sequence is 0,...,10 and 3,4,5 and -5,-4,-2 but % NOT 0,2,4 or 4,10. % % Furthermore, any NON-integer tick arguments are also assumed to be % NOT uniform. % % INPUT: % #1: a tick argument (i.e. something which can be put to % \foreach \x in {#1}) % % OUTPUT: % \pgfplots@isuniformticktrue % or % \pgfplots@isuniformtickfalse % depending on the check. % This variable will be set globally. \def\pgfplots@checkisuniformLOGtick#1{% \begingroup \global\pgfplots@isuniformticktrue \pgfplots@checkuniform@isfirsttrue \foreach \x in {#1}{% \pgfmathmultiply@\x\reciproclogten \let\cur=\pgfmathresult % check whether % \cur - last == 1 (last = \pgfplots@glob@TMPb) \ifpgfplots@checkuniform@isfirst \global\pgfplots@checkuniform@isfirstfalse \else \pgfmathsubtract@\cur\pgfplots@glob@TMPb% \pgfmathapproxequalto@\pgfmathresult{1.0}% \ifpgfmathcomparison \else \global\pgfplots@isuniformtickfalse \breakforeach \fi \fi \global\let\pgfplots@glob@TMPb=\cur }% \endgroup } % Checks whether the linear tick sequence #1 is a uniform tick. % % It also assigns pgfplots@tick@distance@#1 as the distance. % % see \pgfplots@checkisuniformLOGtick for details. % % #1: a tick sequence (expanded) % #2: a macro which will be filled with the tick distance. This is % only valid if \pgfplots@isuniformticktrue. \def\pgfplots@checkisuniformLINEARtick#1#2{% \begingroup \global\pgfplots@isuniformticktrue \pgfplots@checkuniform@isfirsttrue \global\let\pgfplots@glob@TMPb=\pgfutil@empty \global\def\pgfplots@glob@TMPa{1}% \foreach \x in {#1}{% \ifx\pgfplots@glob@TMPb\pgfutil@empty \else \pgfmathsubtract@\x\pgfplots@glob@TMPb \ifpgfplots@checkuniform@isfirst % remember first distance h = x_1 - x_0 \global\let\pgfplots@glob@TMPa=\pgfmathresult \global\pgfplots@checkuniform@isfirstfalse \else % check whether x_i - x_{i-1} = h \pgfmathapproxequalto@\pgfmathresult\pgfplots@glob@TMPa% \ifpgfmathcomparison \else \global\pgfplots@isuniformtickfalse \breakforeach \fi \fi \fi \global\let\pgfplots@glob@TMPb=\x% }% \endgroup \let#2=\pgfplots@glob@TMPa } % helper method which computes log10*\x foreach \x in {#1}. % The result will be \xdef'ed into #2. % % #1: the ticks % #2: the output macro % #3: the axis \def\pgfplots@compute@tick@times@logten#1\to#2#3{% \global\let#2=\pgfutil@empty \foreach \pgfplots@loc@TMPb in {#1} {% \pgfmathmultiply@{\pgfplots@loc@TMPb}{\csname pgfplots@log@scale@todisplaylog@#3\endcsname}% \ifx#2\pgfutil@empty \xdef#2{\pgfmathresult}% \else \xdef#2{#2,\pgfmathresult}% \fi }% } % Computes tick positions using the current axis limits. % % Parameters: % /pgfplots/max space between ticks % Determines the maximum space which is not filled by at least one % tick label (approximate, there is some rounding internally) % /pgfplots/try min ticks % see manual % % Idea: % We want ticks at each % { i*H, i in \Z }. % Of course, there shouldn't be TOO MUCH ticks. % % Our heuristics is to set % desirednumticks = round(ACTUAL WIDTH / (max space between ticks) ) % and generate H = (axis range) / (desirednumticks). % % Since not all step sizes H look well, restrict H to a set of allowed % step sizes such as % { 1, 1/2, 1/5, 1/10 }, % or, to be more precise: % { 1*10^e, 2*10^e, 5*10^e } % -> round to the nearest matching number! % This yields H (for example as 2*10^e). Then, compute i*H, i \in \Z % % The data scaling transformation T(x) makes things more complicated. % Now, T(x) = q * x - p and we need to check for problems with large % numbers: % - q* H = ( T(Max) - T(Min) ) / desirednumticks = q * (Max - Min) / desirednumticks. % - Using floating point arithmetics, (Max-Min)/desirednumticks (unscaled!) % is analysed to restrict H to {1*10^e, 2*10^e, 5*10^e}. % - So, we get q * H (we can't use the 'p' shift of the affine trafo here). % - The next problem is to compute { I*H, I in \Z } because % I = trunc( Min / H ) = trunc( ( T(Min) + p ) / (q*H) ). % This can be seen by Min = I*H + rest and thus T(Min) = I*q*H + q*rest -p. % The Problem: (T(min)+p ) / (q*H) can be TOO BIG for pgfmath. % -> for the data scaling case, I will use floating point % arithmetics to compute that last step. % I will acquire \pgfplots@[xy]min@unscaled@as@float here. % % % % % % For log-plots, % H in { j*log(10), j=1,2,3,... } % where the usual case should be j = 1. % % Then, the resulting tick is % TICK={MIN,MIN+H,...,MAX} % where % MIN = I*H % is chosen such that % axis minimum limit = I*H + rest; |rest| < H. % % Again, log plots follow a slightly different approach: here, % MIN = I * log(10) % is chosen such that % axis minimum limit = I*log(10) + rest; |rest| < log(10) % while H = j*log(10), j>=1. % % % PRECONDITION: % - limits are correct % - axis width/height is set correctly % % POSTCONDITION: % - Tick for axis #1 is assigned % - \ifpgfplots@determinedefaultvalues@needs@check@uniformtick is set % % REMARKS: % - this algorithms works also if the data range has been transformed % with a LINEAR transformation. % ATTENTION: as of 2008-05-15, the scaling trafo is AFFINE LINEAR. % That means we have to eliminate the 'affine' shifting before the % algorithms works correctly. \def\pgfplots@assign@default@tick@foraxis#1{% \begingroup % Shortcut-names: \expandafter\let\expandafter\ifpgfplots@is@datascaled\csname ifpgfplots@apply@datatrafo@#1\endcsname % Attention here: use UNSHIFTET scalings, see remark above \expandafter\let\expandafter\pgfplots@data@scale@trafo\csname pgfplots@datascaletrafo@#1@noshift\endcsname \expandafter\let\expandafter\pgfplots@data@scale@inverse@trafo\csname pgfplots@inverse@datascaletrafo@#1@noshift\endcsname \expandafter\let\expandafter\ifpgfplots@cur@is@linear\csname ifpgfplots@#1islinear\endcsname % \let\desirednumticks=\c@pgf@countd \let\Wr=\pgf@xc \Wr=\csname pgfplotspoint#1axislength\endcsname\relax % r = max place without ticks in pt -> choose desirednumticks >= W/r \divide\Wr by\axisdefaulttickwidth\relax \afterassignment\pgfplots@gobble@until@relax \desirednumticks=\the\Wr\relax \advance\desirednumticks by1 \csname ifpgfplots@#1islinear\endcsname \ifnum\axisdefaulttryminticks>\desirednumticks\relax \desirednumticks=\axisdefaulttryminticks\relax \fi \else \ifnum\pgfplots@default@try@minticks@log>\desirednumticks\relax \desirednumticks=\pgfplots@default@try@minticks@log\relax \fi \expandafter\ifx\csname pgfplots@#1tickten\endcsname\pgfutil@empty \else % log plot and tickten-option: provide special processing. \edef\pgfplots@loc@TMPa{\csname pgfplots@#1tickten\endcsname}% \expandafter\pgfplots@compute@tick@times@logten\pgfplots@loc@TMPa\to\pgfplots@glob@TMPa{#1}% \expandafter\let\csname pgfplots@#1tick\endcsname=\pgfplots@glob@TMPa \fi \fi % \expandafter\ifx\csname pgfplots@#1tick\endcsname\pgfutil@empty % Ok, we have either log or linear axis and need default % ticks MIN,MIN+H,...,MAX. \let\MINH=\pgf@xa \let\H=\pgf@xb \let\MAX=\pgf@ya \let\MIN=\pgf@yb % compute step size 'H': \expandafter\MAX\csname pgfplots@#1max\endcsname pt % \advance\MAX by0.001pt % avoid round errors %\expandafter\MIN\the\c@pgf@counta pt \expandafter\MIN\csname pgfplots@#1min\endcsname pt % \H=\MAX \advance\H by-\MIN %\message{Axis limit #1: [\the\MIN:\the\MAX], diff = \the\H.}% \c@pgf@counta=\desirednumticks \advance\c@pgf@counta by-1 % \divide\H by\c@pgf@counta %\message{determining ticks for #1-axis: Wr := (width/max space between ticks) = \the\Wr, desirednumticks=max(\axisdefaulttryminticks, trunc(Wr)) = \the\desirednumticks, H#1=(axis range/(desirednumticks-1)) = \the\H}% % % SEARCH for the NEXT FEASABLE H. \edef\Hmacro{\pgf@sys@tonumber\H}% \ifpgfplots@cur@is@linear % CASE LINEAR AXIS \ifpgfplots@is@datascaled % This here works if the scaling trafo is linear. \expandafter\pgfplots@data@scale@inverse@trafo\expandafter{\Hmacro}% \let\Hmacro=\pgfmathresult \else \pgfmathfloatparsenumber{\Hmacro}% \let\Hmacro=\pgfmathresult \fi \expandafter\pgfmathfloat@decompose\pgfmathresult\relax\pgfmathfloat@a@S\H\pgfmathfloat@a@E %\message{Got T^{-1}(H#1) = \Hmacro}% % modify the mantisse: \ifdim\H<2pt \ifdim\H<1.5pt \H=1.0pt \else \H=2.0pt \fi \else \ifdim\H<4.9999pt \ifdim\H<3.5pt \H=2.0pt\relax \else \H=5.0pt\relax \fi \else \ifdim\H<7.5pt \H=5.0pt\relax \else \H=1.0pt\relax \advance\pgfmathfloat@a@E by1 \fi \fi \fi \aftergroup\pgfplots@isuniformticktrue \pgfmathfloatcreate{\the\pgfmathfloat@a@S}{\pgf@sys@tonumber{\H}}{\the\pgfmathfloat@a@E}% \let\Hmacro=\pgfmathresult % The following code is carried out in floating point % arithmetics because it requires large data ranges. % % I want to compute MIN@new := I*H where I is chosen % such that MIN = I*H + rest with rest < H. % The problem is the possibly large range of MIN. I % can't work completely in the transformed datarange, % so numbers get too large. % % So, compute I := int( MIN / H ) (integer truncation) % in float arithmetics and then MIN@new := I*H \pgfmathfloatdivide@{\csname pgfplots@#1min@unscaled@as@float\endcsname}{\Hmacro}% \pgfmathfloatint@{\pgfmathresult}% \pgfmathfloatmultiply@{\pgfmathresult}{\Hmacro}% \let\MIN@new=\pgfmathresult % Ok, we are ready. % Now, convert everything into the fixed point data % range: \ifpgfplots@is@datascaled \csname pgfplots@datascaletrafo@#1\endcsname{\MIN@new}% \MIN=\pgfmathresult pt \pgfplots@data@scale@trafo\Hmacro \H=\pgfmathresult pt \else \pgfmathfloattofixed\MIN@new \MIN=\pgfmathresult pt \pgfmathfloattofixed\Hmacro \H=\pgfmathresult pt \fi % % And, since we have used finite precision, I is most % likely to be large. So: subtract one H. In the worst % case, this produces one tick position too much (but % it won't be printed). \advance\MIN by-\H\relax \else % CASE LOG AXIS % % search for the "best" H= j* log(10), j an integer. % % And prefer j=1 if that is possible (otherwise minor % ticks are not useful). \pgfmathmultiply@{\Hmacro}{\csname pgfplots@log@scale@todisplaylog@#1@inv\endcsname}% \let\Hmacrobaseten=\pgfmathresult \expandafter\H\pgfmathresult pt %\message{ [ H / log(10) = \pgfmathresult ]}% \ifdim\H<2pt \H=1pt \else \ifnum\H<1pt \H=1pt \else \expandafter\pgfmathfloor\expandafter{\pgfmathresult}% \expandafter\H\pgfmathresult pt \fi \fi \ifdim\H=1pt \aftergroup\pgfplots@isuniformticktrue \pgfplots@isuniformticktrue \else \aftergroup\pgfplots@isuniformtickfalse \pgfplots@isuniformtickfalse \fi %\message{final H=\pgf@sys@tonumber{\H} * log(10)}% \H=\csname pgfplots@log@scale@todisplaylog@#1\endcsname\H\relax % Now, we want to activate the Tick set % {lowest, lowest+H, ..., highest} % % Where % lowest = I * log(10) + rest, |rest| < log(10). % this is conceptionally different from the approach for % linear axes, because H = j*log(10). % % remember the original xmin in MINH: \MINH=\MIN % % and compute I and I*log(10) here: \MIN=\csname pgfplots@log@scale@todisplaylog@#1@inv\endcsname\MIN\relax \edef\pgfmathresult{\pgf@sys@tonumber{\MIN}}% \pgfmathsetcount{\c@pgf@counta}{\pgfmathresult}% \ifdim\MIN<0pt % the truncation rounds TOWARDS 0 which is not what I want. \advance\c@pgf@counta by-1 \fi \MIN=\csname pgfplots@log@scale@todisplaylog@#1\endcsname pt \multiply\MIN by\c@pgf@counta \ifpgfplots@isuniformtick \else % This here is a special case to move the first tick % near the lower axis limit. % % "Near" means either directly above or directly below ymin. % % My application example is as follows: % Let H = 2*log(10). % Furthermore, ymin = 3e-6, ymax= 8e-2. That means we can choose either % 10^{-5}, 10^{-3}, 10^{-1} % or % 10^{-4}, 10^{-2} % as ticks. Well, I prefer the first one. % % HEURISTICS: start as near to ymin as possible! % % We check here if we can come nearer to ymin if we % shift the current tick by log(10): % if( ymin - I * log(10) < 0.5*H -> use I+1, that means add log(10). % % that's equivalent to % 2*(ymin - I * log(10)) - H < 0. \advance\MINH by-\MIN \multiply\MINH by2 \advance\MINH by-\H % \ifdim\MINH<0pt \advance\MIN \csname pgfplots@log@scale@todisplaylog@#1\endcsname pt \fi \fi \fi \MINH=\MIN \advance\MINH by\H % Ok, now it can happen that only ONE tick label is placed in % this range. % That's useless, so check for it. % % That's the case if % MIN < ORIGMIN && MAX < MIN+2 H % MIN < ORIGMIN by construction (ok, MIN <= ORIGMIN by % construction, but I don't care about this case). % So: check only the second condition. \def\pgfplots@tick@returnval@ready{0}% \pgfplots@tmpa=\MINH \advance\pgfplots@tmpa by\H \ifdim\MAX<\pgfplots@tmpa \pgfplots@if{pgfplots@#1islinear}{% \def\pgfplots@tick@returnval@ready{1}% \begingroup \c@pgf@counta=\axisdefaulttryminticks\relax \advance\c@pgf@counta by1 \edef\axisdefaulttryminticks{\the\c@pgf@counta}% %\message{**TOO FEW TICK LABELS. RECURSION with try min ticks=\axisdefaulttryminticks.**}% % recurse. \pgfplots@assign@default@tick@foraxis{#1}% \expandafter\global\expandafter\let\expandafter\pgfplots@glob@TMPa\csname pgfplots@#1tick\endcsname \expandafter\global\expandafter\let\expandafter\pgfplots@glob@TMPb\csname pgfplots@tick@distance@#1\endcsname \endgroup }{% \aftergroup\pgfplots@isuniformtickfalse % ok, do something special. % % The idea is now to place ticks at % 10^{i*h} with properly choosen 'h'. % % So: apply basically the SAME code as above for linear % axis, just everything log 10! And keep in mind that all % coordinates are actually given as natural logarithms. \expandafter\MIN\csname pgfplots@#1min\endcsname pt \H=\MAX \advance\H by-\MIN \H=\csname pgfplots@log@scale@todisplaylog@#1@inv\endcsname\H %\message{Axis limit #1: [\the\MIN:\the\MAX], diff/log(10) = \the\H.}% \c@pgf@counta=\desirednumticks\relax \advance\c@pgf@counta by-1 \ifnum\c@pgf@counta>2 % subtract one more. This algorithm here produces more % ticks than the normal one which is designed for 10^i \advance\c@pgf@counta by-1 \fi \divide\H by\c@pgf@counta\relax %\message{determining ticks for #1-axis: Wr := (width/max space between ticks) = \the\Wr, desirednumticks=max(\axisdefaulttryminticks, trunc(Wr)) = \the\desirednumticks, H#1=(axis range/(desirednumticks-1)) = \the\H}% % % SEARCH for the NEXT FEASABLE H. \edef\Hmacro{\pgf@sys@tonumber\H}% \pgfmathfloatparsenumber{\Hmacro}% \expandafter\pgfmathfloat@decompose\pgfmathresult\relax\pgfmathfloat@a@S\H\pgfmathfloat@a@E % Determine properly snapped mantisse... \ifdim\H<2pt \ifdim\H<1.5pt \H=1.0pt \else \H=2.0pt \fi \else \ifdim\H<4.9999pt \ifdim\H<3.5pt \H=2.0pt\relax \else \H=5.0pt\relax \fi \else \ifdim\H<7.5pt \H=5.0pt\relax \else \H=1.0pt\relax \advance\pgfmathfloat@a@E by1 \fi \fi \fi \pgfmathfloatcreate{\the\pgfmathfloat@a@S}{\pgf@sys@tonumber{\H}}{\the\pgfmathfloat@a@E}% \expandafter\pgfmathfloattofixed\expandafter{\pgfmathresult}% \let\Hmacro=\pgfmathresult \H=\Hmacro pt % % Ok, our step size h for 10^{i*h} is ready! %\message{determined step size 10^{\Hmacro}}% % Now, we want to activate the Tick set {10^{i*H}, i in \Z} % compute I such that % 10^{min} = 10^{I * H + rest}; |rest| < H % -> I = round(xmin/H) % -> MIN = I * H % BUT EVERYTHING to log(10) basis! \MIN=\csname pgfplots@log@scale@todisplaylog@#1@inv\endcsname \MIN\relax \pgfmathlog@invoke@expanded\pgfmathdivide@{% {\pgf@sys@tonumber\MIN}% {\Hmacro}% }% \pgfmathsetcount{\c@pgf@counta}{\pgfmathresult}% \ifdim\MIN<0pt % the truncation rounds TOWARDS 0 which is not what I want. \advance\c@pgf@counta by-1 \fi \MIN=\H\relax \multiply\MIN by\c@pgf@counta\relax % % convert back to basis 'e': \MIN=\csname pgfplots@log@scale@todisplaylog@#1\endcsname\MIN\relax \H=\csname pgfplots@log@scale@todisplaylog@#1\endcsname\H\relax \MINH=\MIN\relax \advance\MINH by\H\relax }% \fi %\message{final H=\the\H.}% \if0\pgfplots@tick@returnval@ready \xdef\pgfplots@glob@TMPb{\pgf@sys@tonumber{\H}}% \advance\MAX by0.5\H % avoid rounding inaccuracies: \xdef\pgfplots@glob@TMPa{\pgf@sys@tonumber{\MIN},\pgf@sys@tonumber{\MINH},...,\pgf@sys@tonumber{\MAX}}% \fi \aftergroup\pgfplots@determinedefaultvalues@needs@check@uniformtickfalse \else \expandafter\global\expandafter\let\expandafter\pgfplots@glob@TMPa\csname pgfplots@#1tick\endcsname \gdef\pgfplots@glob@TMPb{}% will be computed later, in 'check uniform tick' \aftergroup\pgfplots@determinedefaultvalues@needs@check@uniformticktrue \fi \endgroup \expandafter\let\csname pgfplots@#1tick\endcsname=\pgfplots@glob@TMPa \expandafter\let\csname pgfplots@tick@distance@#1\endcsname=\pgfplots@glob@TMPb %\message{pgfplots.sty: #1tick set to \csname pgfplots@#1tick\endcsname [#1min=\csname pgfplots@#1min\endcsname, #1max=\csname pgfplots@#1max\endcsname].}% } % Helper method for % \pgfplots@apply@data@scale@trafo@to@options@for % #1: the ticks % #2: the trafo macro name % #3: the output macro name \long\def\pgfplots@apply@data@scale@trafo@to@user@ticks#1#2\to#3{% \let#3=\pgfutil@empty \foreach \pgfplots@loc@TMPb in {#1} {% \pgfmathfloatparsenumber{\pgfplots@loc@TMPb}% \expandafter#2\expandafter{\pgfmathresult}% \ifx#3\pgfutil@empty \xdef#3{\pgfmathresult}% \else \xdef#3{#3,\pgfmathresult}% \fi }% % }% % Helper method for % \pgfplots@apply@data@scale@trafo@to@options@for % #1: the ticks ALREADY IN FLOAT FORMAT % #2: the trafo macro name % #3: the output macro name \long\def\pgfplots@apply@data@scale@trafo@to@user@ticks@isfloat#1#2\to#3{% \let#3=\pgfutil@empty \foreach \pgfplots@loc@TMPb in {#1} {% #2{\pgfplots@loc@TMPb}% \ifx#3\pgfutil@empty \xdef#3{\pgfmathresult}% \else \xdef#3{#3,\pgfmathresult}% \fi }% % }% % Adds a further, temporary anchor to every node which will be % processed. The anchor will be named '#2'. It is placed such that % 1. the node's center is on a line in direction of the inwards normal % vector of the #1 ticklabel axis and the 'at' position of the node, % 2. the node does not intrude the axis. % % In effect, one of the node's standard anchors (north, east, ... ) % will be placed on the line % \draw[blue,thick,->] (xticklabel cs:0,0) -- (xticklabel cs:1,0); % % This command is identical to calling % \pgfplotsdeclareborderanchorforaxis{#1}{}{#2} % % @REMARKS: % - it is -by no means- necessary that any ticks or tick labels are % drawn or defined for this method. % - in fact, tick labels use such an anchor (the 'near #1ticklabel' % anchor is defined in this way) \def\pgfplotsdeclareborderanchorforticklabelaxis#1#2{% \pgfplotsdeclareborderanchorforaxis{#1}{\pgfplotsticklabelaxisspec{#1}}{#2}% }