工程符号(科学)作为带有 pgfplots 的刻度标签(可能通过 siunitx)?

工程符号(科学)作为带有 pgfplots 的刻度标签(可能通过 siunitx)?

我希望刻度标签上的数字以工程符号格式显示——但与如何控制 pgfplots 轴缩放以进行工程符号表示(3 指数的倍数)?,我希望没有scaled ticks(也就是说,10^x如果合适的话,每个刻度都应该显示其指数)。

我得到了这个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}

...渲染结果如下:

测试01.png

所以我有:

  • 0.5、1、5、10、50、100、500、1000、5000、10000、50000、100000 - 作为 x 刻度(和标签)的原始序列,
  • 10 -0.3 , 10 0 , 10 0.7 , 10 1 , ... - 作为 x 刻度标签,如pgfplots
  • 0.5;1;5;... 50,000;1·10 5 - 输出为\pgfmathprintnumber(左,蓝色)
  • 500×10 -3 , 1, 5, ..., 50×10 3 , 100×10 3 - 作为(右,黑色)\num的输出siunitx

我希望的是,不是使用当前的 x 个刻度标签数字,而是使用siunitx工程符号格式来呈现 x 个刻度标签 - 但是:使用\!\cdot\!尾数分隔符,而不是\times; 并且不使用千位分隔符。我该如何实现这一点?

答案1

好的,我想我已经了解了大部分内容 - 除了现在有一个“指数往返”会导致舍入误差(见下图);如果有人知道如何避免这种情况,请发表答案。

测试011.png

正是那些 500.12e-3 和 499.97 xtick 值显示了舍入误差;这里的问题是\tick这里的变量是对数的(实际上是 ln 的),所以我必须对它进行指数运算 - 这需要使用fpu,然后回到定点;当我们回到原始 xtick 值域时,那些值已经被“损坏”:显示\typeout

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

否则,就会siunitx通过\num使用xticklabel图的键来完成工程符号格式化。

以下是 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}

答案2

我遇到了类似的问题,只是我想要 SI 前缀。我根据这个情况调整了你的代码。可能不是最干净的解决方案,但到目前为止有效。我还添加了舍入功能,以便可以修复损坏的值(当然,会丢失小数精度)

结果图片

\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}

相关内容