3

I would like to have numbers on the ticks labels formatted in engineering notation -- but unlike in How to control pgfplots axis scaling for engineering notation (multiple of 3 exponent)?, I would like not to have scaled ticks (that is, each tick should display its 10^x exponent, if appropriate).

I got to this MWE:

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.5.1}
\usepackage{tikz}
\usepackage{siunitx}
\usepackage[pdftex,active,tightpage]{preview}

\begin{document}

\pgfkeys{
  /pgf/number format/sci generic={mantissa sep={\!\cdot\!},exponent={10^{#1}}},
}

\begin{preview}
\begin{tikzpicture}
\begin{axis}[
  axis x line=bottom,
  axis y line=left,
  scaled ticks=false,
  xmode=log,
  /pgfplots/xtick={0,0.5,1,5,10,50,100,500,1000,5000,10000,50000,100000},
  x tick label style={rotate=-50, anchor=west, align=center, font=\small},
  xmin=0, xmax=200000,
  ymin=0,
  visualization depends on={rawx \as \myx},
  nodes near coords={($\pgfmathprintnumber\myx$, \textcolor{black}{\num[scientific-notation = engineering,round-mode=places,round-precision=2,zero-decimal-to-integer]{\myx}}\color{blue})},
]

\addplot[color=blue,mark=*] coordinates
  { (0.5,1) (1,2) (5,3) (10,4) (50,5) (100,6) (500,7)
    (1000,8) (5000,9) (10000,10) (50000,11) (100000,12)};

\end{axis}
\end{tikzpicture}
\end{preview}

\end{document}

... which results with this rendering:

test01.png

So, I have:

  • 0.5, 1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000 - as the original sequence for the x ticks (and labels),
  • 10-0.3, 100, 100.7, 101, ... - as the x tick labels as done by pgfplots
  • 0.5; 1; 5; ... 50,000; 1·105 - as output by \pgfmathprintnumber (left, blue)
  • 500×10-3, 1, 5, ..., 50×103, 100×103 - as output by \num of siunitx (right, black)

What I'd like to have, is that instead of the current x ticks label numbers, the siunitx engineering notation format is rendered for the x ticks labels - but: with \!\cdot\! as mantissa separator, instead of \times; and without thousands separator. How could I achieve this?

5

Ok, I think I got most of it - except, now there is an "exponentiation roundtrip" which causes rounding errors (see pic below); if anyone knows how to avoid it that, please post an answer.

test011.png

It is those 500.12e-3 and 499.97 xtick values that show the rounding errors; the problem here is that the \tick variable here is logarithm'd (actually, ln'd), so I have to exponentiate it -- and that requires use of fpu, and then coming back to fixed point; and by the time we've gotten back to the original xtick values domain, those values are already "corrupted": the \typeout shows:

tick -0.69316,  tmp 0.50012
tick  0.0,      tmp 1.0000000000
tick  1.60942,  tmp 4.99974000000000
tick  2.30258,  tmp 10.000000000
tick  3.912,    tmp 49.9974000000000
tick  4.60516,  tmp 100.00000000
tick  6.21458,  tmp 499.974000000000
tick  6.90775,  tmp 1000.0000000
tick  8.51717,  tmp 4999.74000000000
tick  9.21033,  tmp 10000.000000
tick 10.81975,  tmp 49997.4000000000
tick 11.51291,  tmp 100000.00000

Otherwise, it is siunitx's \num that does the engineering notation formatting - through the use of the xticklabel key of the plot.

Here is the MWE:

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.5.1}
\usepackage{tikz}
\usepackage{siunitx}
\usepackage[pdftex,active,tightpage]{preview}

\begin{document}

\pgfkeys{
  /pgf/number format/sci generic={mantissa sep={\!\cdot\!},exponent={10^{#1}}},
}

% use \newcommand (not \def), so the one (and only)
% argument can be specified in {} (and not in []) brackets
\newcommand{\mynum}[1]{
  % =\pgfmathparse{e^\tick}\pgfmathresult : ! Dimension too large. ; - use exp(x)
  \pgfkeys{/pgf/fpu}% else dimension too large!
  \pgfmathparse{exp(#1)}%
  % \edef\tmp{\pgfmathresult}%
  % \pgfmathprintnumberto{\pgfmathresult}{\tmp}% nope, gives 1Y5.0012e-1]
  \pgfmathfloattofixed{\pgfmathresult}% also outputs in \pgfmathresult
  \edef\tmp{\pgfmathresult}%
  \pgfkeys{/pgf/fpu=false}%
  \typeout{tick #1, tmp \tmp}%
  \num[%
    scientific-notation=engineering,%
    round-mode=places,%
    round-precision=2,%
    zero-decimal-to-integer,%
    group-digits=false,%
    exponent-product=\!\cdot\!,%
  ]{\tmp} %
}

\begin{preview}
\begin{tikzpicture}
\begin{axis}[
  axis x line=bottom,
  axis y line=left,
  scaled ticks=false,
  xmode=log,
  /pgfplots/xtick={0,0.5,1,5,10,50,100,500,1000,5000,10000,50000,100000},
  x tick label style={rotate=-50, anchor=west, align=center, font=\small},
  xmin=0, xmax=200000,
  ymin=0,
  visualization depends on={rawx \as \myx}, % , \tick \as \myxt
  nodes near coords={($\pgfmathprintnumber\myx$, \textcolor{black}{\num[scientific-notation = engineering,round-mode=places,round-precision=2,zero-decimal-to-integer]{\myx}}\color{blue})},
  % cannot use options to \num here, we're already in options,
  % so extra [], like below, will cause "! Missing \endcsname inserted."
%   xticklabel=\num[scientific-notation=engineering,round-mode=places,round-precision=2,zero-decimal-to-integer]{123},
  % so, use a \newcommand ( \mynum ) here:
  xticklabel=\mynum{\tick}, % \myx undefined here, \tick is logarithm'd!
]

\addplot[color=blue,mark=*] coordinates
  { (0.5,1) (1,2) (5,3) (10,4) (50,5) (100,6) (500,7)
    (1000,8) (5000,9) (10000,10) (50000,11) (100000,12)};

\end{axis}
\end{tikzpicture}
\end{preview}

\end{document}
4

I was facing a similar problem, except that I wanted to have SI prefixes. I adapted your code to that. Might not be the cleanest solution, but works so far. I also added a rounding capability so that the corrupted values can be fixed (by losing decimal precision of course)

Image of the result

\documentclass{article}
\usepackage{tikz,amsmath, amssymb,bm,color,pgfkeys,siunitx,ifthen}
\usepackage{pgfplots}
\pgfplotsset{compat=1.14}
\usepackage[pdftex,active,tightpage]{preview}

\begin{document}

    % use \newcommand (not \def), so the one (and only)
    % argument can be specified in {} (and not in []) brackets
    \newcommand{\engticksilabel}[1]{
        \pgfmathparse{0}% precision
        \edef\numtoengprecision{\pgfmathresult}%
        \pgfkeys{/pgf/fpu}% else dimension too large!
        \pgfmathparse{(#1)}% % eng labels come out as logarithms
        \edef\numtoengraw{\pgfmathresult}%
        \pgfmathparse{round((\numtoengraw)*10^6)/(10^6)}%
        \pgfmathfloattosci\pgfmathresult
        \edef\numtoengroundedraw{\pgfmathresult}%
        \pgfmathparse{floor(log10(\numtoengraw)/(log10(1000.0)))}%
        \edef\numtoengexpthree{\pgfmathresult}%
        \pgfmathparse{(\numtoengraw)*(1000^((-1.0)*\numtoengexpthree))}%
        \edef\numtoenginputnormalized{\pgfmathresult}%
        \pgfmathparse{3*\numtoengexpthree}%
        \pgfmathfloattofixed\pgfmathresult%
        \edef\numtoengexpten{\pgfmathresult}%
        \pgfmathparse{round(\numtoenginputnormalized*10^\numtoengprecision)*(10^(-1*\numtoengprecision))}%
        \pgfmathfloattofixed\pgfmathresult%
        \edef\numtoenginputnormalizedrounded{\pgfmathresult}%
        \pgfmathparse{ifthenelse(or(\numtoengexpthree<-(18/3),\numtoengexpthree>(18/3)),1,0)}% too small
        \pgfmathfloattoint{\pgfmathresult}%
        \message{raw=\numtoengraw,exp3=\numtoengexpthree,normalized=\numtoenginputnormalized,normalizedrounded=\numtoenginputnormalizedrounded}%
        \ifthenelse{\equal{\pgfmathresult}{1}}%
        {%
            \edef\engtonumnumber{\num[%
                scientific-notation=engineering,%
                exponent-to-prefix=true,
                round-mode=places,%
                round-precision=3,%
                zero-decimal-to-integer,%
                group-digits=false,%
                exponent-product=\!\cdot\!,%
                ]{\numtoenginputnormalizedrounded}} 
            \edef\engtonumexptennumber{\num[%
                scientific-notation=engineering,%
                exponent-to-prefix=true,
                round-mode=places,%
                round-precision=3,%
                zero-decimal-to-integer,%
                group-digits=false,%
                exponent-product=\!\cdot\!,%
                ]{\numtoengexpten}}% 
            \def\numtoengsiprefix{{\cdot} 10^{\engtonumexptennumber}}%
        }{% else: normal number format
            \edef\engtonumnumber{\num[%
                scientific-notation=engineering,%
                exponent-to-prefix=true,
                round-mode=places,%
                round-precision=3,%
                zero-decimal-to-integer,%
                group-digits=false,%
                exponent-product=\!\cdot\!,%
                ]{\numtoenginputnormalizedrounded}}% 
        }%
        \pgfmathparse{ifthenelse(\numtoengexpthree==-(18/3),1,0)}%
        \pgfmathfloattoint{\pgfmathresult}%
        \ifthenelse{\equal{\pgfmathresult}{1}}%
        {\edef\numtoengsiprefix{\si{\atto}}}{}%
        \pgfmathparse{ifthenelse(\numtoengexpthree==-(15/3),1,0)}%
        \pgfmathfloattoint{\pgfmathresult}%
        \ifthenelse{\equal{\pgfmathresult}{1}}%
        {\edef\numtoengsiprefix{\si{\femto}}}{}%
        \pgfmathparse{ifthenelse(\numtoengexpthree==-(12/3),1,0)}%
        \pgfmathfloattoint{\pgfmathresult}%
        \ifthenelse{\equal{\pgfmathresult}{1}}%
        {\edef\numtoengsiprefix{\si{\pico}}}{}%
        \pgfmathparse{ifthenelse(\numtoengexpthree==-(9/3),1,0)}%
        \pgfmathfloattoint{\pgfmathresult}%
        \ifthenelse{\equal{\pgfmathresult}{1}}%
        {\edef\numtoengsiprefix{\si{\nano}}}{}%
        \pgfmathparse{ifthenelse(\numtoengexpthree==-(6/3),1,0)}%
        \pgfmathfloattoint{\pgfmathresult}%
        \ifthenelse{\equal{\pgfmathresult}{1}}%
        {\edef\numtoengsiprefix{\si{\micro}}}{}%
        \pgfmathparse{ifthenelse(\numtoengexpthree==-(3/3),1,0)}%
        \pgfmathfloattoint{\pgfmathresult}%
        \ifthenelse{\equal{\pgfmathresult}{1}}%
        {\edef\numtoengsiprefix{\si{\milli}}}{}%
        \pgfmathparse{ifthenelse(\numtoengexpthree==(0/3),1,0)}%
        \pgfmathfloattoint{\pgfmathresult}%
        \ifthenelse{\equal{\pgfmathresult}{1}}%
        {\edef\numtoengsiprefix{}}{}%   
        \pgfmathparse{ifthenelse(\numtoengexpthree==(3/3),1,0)}%
        \pgfmathfloattoint{\pgfmathresult}%
        \ifthenelse{\equal{\pgfmathresult}{1}}%
        {\edef\numtoengsiprefix{\si{\kilo}}}{}%
        \pgfmathparse{ifthenelse(\numtoengexpthree==(6/3),1,0)}%
        \pgfmathfloattoint{\pgfmathresult}%
        \ifthenelse{\equal{\pgfmathresult}{1}}%
        {\edef\numtoengsiprefix{\si{\mega}}}{}%
        \pgfmathparse{ifthenelse(\numtoengexpthree==(9/3),1,0)}%
        \pgfmathfloattoint{\pgfmathresult}%
        \ifthenelse{\equal{\pgfmathresult}{1}}%
        {\edef\numtoengsiprefix{\si{\giga}}}{}%
        \pgfmathparse{ifthenelse(\numtoengexpthree==(12/3),1,0)}%
        \pgfmathfloattoint{\pgfmathresult}%
        \ifthenelse{\equal{\pgfmathresult}{1}}%
        {\edef\numtoengsiprefix{\si{\tera}}}{}%
        \pgfmathparse{ifthenelse(\numtoengexpthree==(15/3),1,0)}%
        \pgfmathfloattoint{\pgfmathresult}%
        \ifthenelse{\equal{\pgfmathresult}{1}}%
        {\edef\numtoengsiprefix{\si{\peta}}}{}%
        \pgfmathparse{ifthenelse(\numtoengexpthree==(18/3),1,0)}%
        \pgfmathfloattoint{\pgfmathresult}%
        \ifthenelse{\equal{\pgfmathresult}{1}}%
        {\edef\numtoengsiprefix{\si{\exa}}}{}%
        {$\engtonumnumber\numtoengsiprefix$}%\numtoengsiprefix$}
    }


    \begin{preview}
        \begin{tikzpicture}
        \begin{axis}[
        axis x line=bottom,
        axis y line=left,
        scaled ticks=false,
        xmode=log,
        /pgfplots/xtick={0,0.5,1,5,10,50,100,500,1000,5000,10000,50000,100000},
        x tick label style={rotate=-50, anchor=west, align=center, font=\small},
        xmin=0, xmax=200000,
        ymin=0,
        visualization depends on={rawx \as \myx}, % , \tick \as \myxt
        nodes near coords={($\pgfmathprintnumber\myx$, \textcolor{black}{\engticksilabel{\myx}}\color{blue})},
        % cannot use options to \num here, we're already in options,
        % so extra [], like below, will cause "! Missing \endcsname inserted."
        %   xticklabel=\num[scientific-notation=engineering,round-mode=places,round-precision=2,zero-decimal-to-integer]{123},
        % so, use a \newcommand ( \mynum ) here:
        xticklabel=\engticksilabel{exp(\tick)}, % \myx undefined here, \tick is logarithm'd!
        ]

        \addplot[color=blue,mark=*] coordinates
        { (0.5,1) (1,2) (5,3) (10,4) (50,5) (100,6) (500,7)
            (1000,8) (5000,9) (10000,10) (50000,11) (100000,12)};

        \end{axis}
        \end{tikzpicture}
    \end{preview}

\end{document}
  • Hey, I really like the prefixes. However, I do get a strange problem with the "1" as it's not showing up correctly as described here. Did you encounter anything similar while writing it? Thanks! – John Miller Jul 20 '17 at 12:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.