diff options
Diffstat (limited to 'Master/texmf-dist/tex/generic/pgfplots/pgfplotsticks.code.tex')
-rw-r--r-- | Master/texmf-dist/tex/generic/pgfplots/pgfplotsticks.code.tex | 1530 |
1 files changed, 1530 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/generic/pgfplots/pgfplotsticks.code.tex b/Master/texmf-dist/tex/generic/pgfplots/pgfplotsticks.code.tex new file mode 100644 index 00000000000..cd0cc44dff3 --- /dev/null +++ b/Master/texmf-dist/tex/generic/pgfplots/pgfplotsticks.code.tex @@ -0,0 +1,1530 @@ +%-------------------------------------------- +% +% 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 <http://www.gnu.org/licenses/>. +% +%-------------------------------------------- + +\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 or y) +% #2: the value +% #3,#4: coordinates for \pgfplotspointonorientedsurfaceab +% #5: ticknumber +\def\pgfplots@show@ticklabel#1#2(#3,#4)#5{{% + \csname ifpgfplots@#1ticklabel@interval\endcsname + \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*(\csname pgfplots@show@ticklabel@coord@#1\endcsname + \csname pgfplots@show@ticklabel@coord@#1@new\endcsname)}% + \expandafter\edef\csname pgfplots@show@ticklabel@coord@#1\endcsname{\pgfmathresult}% + \let\ticknum=\pgfplots@show@ticklabel@num\relax% + \let\tick=\pgfplots@show@ticklabel@tick% + \edef\pgfplots@loc@TMPa{at (\pgfplots@show@ticklabel@coord@x,\pgfplots@show@ticklabel@coord@y)}% + \begingroup + \pgftransformshift{\pgfplotspointonorientedsurfaceab{\pgfplots@show@ticklabel@coord@x}{\pgfplots@show@ticklabel@coord@y}}% + \node at (0pt,0pt) {\csname pgfplots@#1ticklabel\endcsname};% + \endgroup + \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}% + \begingroup + \pgftransformshift{\pgfplotspointonorientedsurfaceab{#3}{#4}}% + \node at (0pt,0pt) {\csname pgfplots@#1ticklabel\endcsname};% + \endgroup + \fi +}} + +% 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 + \ifnum\pgfplots@yaxislinesnum=2 % + \ifcase\pgfplots@xaxislinesnum\relax + \ifdim\pgfplots@tmpa=\pgfplots@ymin@reg\relax + \pgfplots@tickshowfalse + \fi + \ifdim\pgfplots@tmpa=\pgfplots@ymax@reg\relax + \pgfplots@tickshowfalse + \fi + \or + \ifdim\pgfplots@tmpa=\pgfplots@ymin@reg\relax + \pgfplots@tickshowfalse + \fi + \or + \ifdim\pgfplots@tmpa=\pgfplots@logical@ZERO@y pt + \pgfplots@tickshowfalse + \fi + \or + \ifdim\pgfplots@tmpa=\pgfplots@ymax@reg\relax + \pgfplots@tickshowfalse + \fi + \fi + \fi +} +\def\pgfplots@ztick@check@tickshow{% + \pgfplots@tickshowtrue + % FIXME +}% + +% 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{% + \ifcase\csname pgfplots@#1tickposnum\endcsname\relax + %(\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 + % (\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 + % (\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 + % (\pgfplots@xcoordmaxTEX+\pgfplots@tick@offset, \pgfplots@tmpa) -- ++(-#2, 0pt); + \edef\pgfplots@tick@beg@a{\csname pgfplots@\pgfplotspointonorientedsurfaceB max\endcsname}% + \pgfmathadd@{\pgfplots@tick@beg@a}{\pgfplots@tick@offset}% + \let\pgfplots@tick@beg@a=\pgfmathresult + \pgfmathsubtract@{\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}}% + \pgftransformshift{\pgfplotspointsouthwest}% + \pgfsetxvec{\pgfplotspointxaxis}% + \pgfsetyvec{\pgfplotspointyaxis}% + % FIXME : do I need the fix for 'current axis.origin' + % here!? + \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 + \ifnum\pgfplots@xaxislinesnum=2 % + \ifcase\pgfplots@yaxislinesnum\relax + \ifdim\pgfplots@tmpa=\pgfplots@xmin@reg\relax + \pgfplots@tickshowfalse + \fi + \ifdim\pgfplots@tmpa=\pgfplots@xmax@reg\relax + \pgfplots@tickshowfalse + \fi + \or + \ifdim\pgfplots@tmpa=\pgfplots@xmin@reg\relax + \pgfplots@tickshowfalse + \fi + \or + \ifdim\pgfplots@tmpa=\pgfplots@logical@ZERO@x pt % + \pgfplots@tickshowfalse + \fi + \or + \ifdim\pgfplots@tmpa=\pgfplots@xmax@reg\relax + \pgfplots@tickshowfalse + \fi + \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}% + \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}% + \expandafter\pgfplots@prepare@tick@coordlists@for\pgfplotspointonorientedsurfaceA{#2}% + \pgfplots@drawgridlines@onorientedsurf% + \pgfplots@drawticklines@onorientedsurf% + \pgfplots@drawticklabels@onorientedsurf% + \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). +\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@minor + \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 + % + % + \foreach \x in {#2} {% + \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 + \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=\logi\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 + }% + \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 + \global\let\pgfplots@prepared@tick@positions@major=\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{% + \begingroup + \expandafter\let\expandafter\ifpgfplots@major\csname ifpgfplots@#1majorgrids\endcsname + \expandafter\let\expandafter\ifpgfplots@minor\csname ifpgfplots@#1minorgrids\endcsname + % grid lines shall be drawn + % if and only if BOTH adjacent axis lines shall be drawn: + \pgfplots@ifaxisline@B@onorientedsurf@should@be@drawn{0}{% + % remark: this is ALWAYS true for 2D plots. + \pgfplots@ifaxisline@B@onorientedsurf@should@be@drawn{1}{% + \def\pgfplots@drawgridlines@onorientedsurf@OK{1}% + }{% + \def\pgfplots@drawgridlines@onorientedsurf@OK{0}% + }% + }{% + \def\pgfplots@drawgridlines@onorientedsurf@OK{0}% + }% + \if1\pgfplots@drawgridlines@onorientedsurf@OK + \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 + \ifpgfplots@major + \pgfplots@loop@CONTINUEtrue + \fi + \ifpgfplots@minor + \pgfplots@loop@CONTINUEtrue + \fi + \ifpgfplots@loop@CONTINUE + \scope + \pgfplots@drawtickgridlines@INSTALLCLIP@onorientedsurf#1 + \ifpgfplots@major + \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; + \fi + % + \ifpgfplots@minor + \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; + \fi + \endscope + \fi + \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}}% + \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{% + \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}% + }% + \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% + \ifnum\csname pgfplots@\pgfplotspointonorientedsurfaceA tickposnum\endcsname=0\relax + \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 + \fi + }% + \endgroup + \expandafter\let\expandafter\ifpgfplots@major\csname ifpgfplots@#1majorticks\endcsname + \expandafter\let\expandafter\ifpgfplots@minor\csname ifpgfplots@#1minorticks\endcsname + \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 + \ifpgfplots@major + \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; + \fi + % + \ifpgfplots@minor + \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; + \fi + \endscope +} + +% Draws tick labels 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') +\def\pgfplots@drawticklabels@onorientedsurf{% + \expandafter\pgfplots@drawticklabels@onorientedsurf@\pgfplotspointonorientedsurfaceA +} +\def\pgfplots@drawticklabels@onorientedsurf@#1{% + \begingroup + \expandafter\let\expandafter\ifpgfplots@major\csname ifpgfplots@#1majorticks\endcsname + \expandafter\let\expandafter\ifpgfplots@islinear\csname ifpgfplots@#1islinear\endcsname + \expandafter\let\expandafter\pgfplots@prepared@tick@positions@major@\csname pgfplots@prepared@tick@positions@major@#1\endcsname + \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 + \ifpgfplots@major + \ifpgfplots@islinear + \pgfplots@init@scaled@tick@for{#1}% + \fi + \begingroup + \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 + % + \pgfkeys{/tikz/every node/.append style={/pgfplots/every tick label,/pgfplots/every #1 tick label}}% + \ifcase\csname pgfplots@#1tickalignnum\endcsname\relax + \def\pgfmathresult{0}% + \or + \pgfmathparse{\pgfplots@tickwidth}% + \or + \pgfmathmultiply{0.5}{\pgfplots@tickwidth}% + \fi + \expandafter\pgfmathmultiply@\expandafter{\pgfmathresult}{\csname pgfplots@\pgfplotspointonorientedsurfaceB @inverseveclength\endcsname}% + \let\pgfplots@tick@offset=\pgfmathresult + %-------------------------------------------------- + % \ifnum\csname pgfplots@#1ticklabelaxisspec\endcsname=0 + % % the choice '[xy]ticklabel pos=default': + % \expandafter\let\expandafter\pgfplots@tmpposnum\csname pgfplots@#1tickposnum\endcsname + % \else + % \expandafter\let\expandafter\pgfplots@tmpposnum\csname pgfplots@#1ticklabelaxisspec\endcsname + % \fi + % \ifcase\pgfplots@tmpposnum\relax + % \expandafter\let\expandafter\pgfplots@tick@origin\csname pgfplots@\pgfplotspointonorientedsurfaceB min\endcsname% + % \or + % \expandafter\let\expandafter\pgfplots@tick@origin\csname pgfplots@\pgfplotspointonorientedsurfaceB min\endcsname% + % \or + % \expandafter\let\expandafter\pgfplots@tick@origin\csname pgfplots@logical@ZERO@\pgfplotspointonorientedsurfaceB\endcsname% + % \or + % \expandafter\let\expandafter\pgfplots@tick@origin\csname pgfplots@\pgfplotspointonorientedsurfaceB max\endcsname% + % \fi + %-------------------------------------------------- + \ifnum\csname pgfplots@#1axislinesnum\endcsname=2 % 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 + \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 + \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 + % + \let\pgfplots@tick@origin=\pgfmathresult% + \def\pgfplots@ticknum{0}% + \xdef\pgfplots@show@ticklabel@LASTTICK{}% + \pgfplotslistforeachungrouped\pgfplots@prepared@tick@positions@major@\as\pgfplots@curtickpos{% + \pgfplots@show@ticklabel + {#1}{\pgfplots@curtickpos}(\pgfplots@curtickpos,\pgfplots@tick@origin)% + {\pgfplots@ticknum}% + \begingroup + \c@pgf@counta=\pgfplots@ticknum\relax + \advance\c@pgf@counta by1 + \edef\pgfplots@ticknum{\the\c@pgf@counta}% + \pgfmath@smuggleone\pgfplots@ticknum + \endgroup + }% + \endgroup + \pgfplots@draw@tick@scale@label@for #1% + \fi + \fi + \endgroup +} + +\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. +\def\pgfplots@compute@tick@times@logten#1\to#2{% + \global\let#2=\pgfutil@empty + \foreach \pgfplots@loc@TMPb in {#1} {% + \pgfmathmultiply@\pgfplots@loc@TMPb\logten% + \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 + % r = max place without ticks in pt -> choose desirednumticks >= W/r + \expandafter\expandafter\divide\Wr\axisdefaulttickwidth + \pgfmathsetcount{\desirednumticks}{\Wr}% + \advance\desirednumticks by1 + \csname ifpgfplots@#1islinear\endcsname + \expandafter\ifnum\axisdefaulttryminticks>\desirednumticks + \desirednumticks=\axisdefaulttryminticks + \fi + \else + \expandafter\ifnum\pgfplots@default@try@minticks@log>\desirednumticks + \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 + \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 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 + \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}{\reciproclogten}% + \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=\logten\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: + \expandafter\MIN\reciproclogten\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 + \expandafter\MIN\logten 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 + \expandafter\advance\expandafter\MIN\logten 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. + \pgfplots@tmpa=\MINH + \advance\pgfplots@tmpa by\H + \ifdim\MAX<\pgfplots@tmpa + \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=\reciproclogten\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=\reciproclogten\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=\logten\MIN\relax + \H=\logten\H\relax + \MINH=\MIN\relax + \advance\MINH by\H\relax + \fi +%\pgfplots@message{final H=\the\H.}% + \xdef\pgfplots@glob@TMPa{\pgf@sys@tonumber{\MIN},\pgf@sys@tonumber{\MINH},...,\pgf@sys@tonumber{\MAX}}% + \xdef\pgfplots@glob@TMPb{\pgf@sys@tonumber{\H}}% + \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 +%\pgfplots@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 + }% + % +}% |