如何控制 pgfplots 轴缩放以进行工程符号表示(3 指数的倍数)?

如何控制 pgfplots 轴缩放以进行工程符号表示(3 指数的倍数)?

pgfplots 的自动十次方缩放功能是一项很棒的功能,它使轴上的数字刻度变得清晰(见图)。但是,由于指数值(例如 10^3、10^4)很难在不同但相似的范围内保持一致性(例如,一个图的数据在 8000 到 9000 之间,另一个图的数据在 11000 到 12000 之间)。此外,如果单位是 SI,如果指数不是 3 的倍数,则人们往往会混淆前缀。

有没有办法强制 pgfplots 仅选择 10 的幂(也是 10^3 的幂)的缩放比例?例如,10^6、10^9、10^12,但绝不会是 10^4 或 10^10。

在这个例子中,选择的功率(由 pgfplot 自动选择 10^10),我怎样才能让它自动选择 10^9(在轴旁边的数字中作相应的更改 --乘以 10--)

权力常常

答案1

缩放由 中的宏处理pgfplotsticks.code.tex。您可以编辑此宏来实现所需的行为。修补宏后,您可以说

\begin{axis}[scaled ticks=engineering]
\addplot {1/10000*rnd};
\end{axis}

将比例因子限制为三的倍数的指数,即所谓的工程符号:

\addplot {1/100*rnd};

\addplot {10000*rnd};

这是您需要放入序言中的代码块:

\makeatletter

\newif\ifpgfplots@scaled@x@ticks@engineering
\pgfplots@scaled@x@ticks@engineeringfalse
\newif\ifpgfplots@scaled@y@ticks@engineering
\pgfplots@scaled@y@ticks@engineeringfalse
\newif\ifpgfplots@scaled@z@ticks@engineering
\pgfplots@scaled@z@ticks@engineeringfalse

\pgfplotsset{
    scaled x ticks/engineering/.code=
        \pgfplots@scaled@x@ticks@engineeringtrue,
    scaled y ticks/engineering/.code=
        \pgfplots@scaled@y@ticks@engineeringtrue,
    scaled z ticks/engineering/.code=
        \pgfplots@scaled@y@ticks@engineeringtrue,
%    scaled ticks=engineering  % Uncomment this line if you want "engineering" to be on by default
}

\def\pgfplots@init@scaled@tick@for#1{%
    \global\def\pgfplots@glob@TMPa{0}%
    \expandafter\pgfplotslistcheckempty\csname pgfplots@prepared@tick@positions@major@#1\endcsname
    \ifpgfplotslistempty
        % we have no tick labels. Omit the tick scale label as well!
    \else
    \begingroup
    \ifcase\csname pgfplots@scaled@ticks@#1@choice\endcsname\relax
    % 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
        \pgfplots@init@scaled@tick@normalize@exponents
        \ifnum\pgfmathfloat@b@E<\pgfmathfloat@a@E
            \pgfmathfloat@b@E=\pgfmathfloat@a@E
        \fi
        \xdef\pgfplots@glob@TMPa{\pgfplots@scale@ticks@above@exponent}%
        \ifnum\pgfplots@glob@TMPa<\pgfmathfloat@b@E
            % ok, scale it:
            \expandafter\ifx % Check whether we're using engineering notation (restricting exponents to multiples of three)
                \csname ifpgfplots@scaled@#1@ticks@engineering\expandafter\endcsname
                \csname iftrue\endcsname
                    \divide\pgfmathfloat@b@E by 3
                    \multiply\pgfmathfloat@b@E by 3
            \fi
            \multiply\pgfmathfloat@b@E by-1
            \xdef\pgfplots@glob@TMPa{\the\pgfmathfloat@b@E}%
        \else
            \xdef\pgfplots@glob@TMPa{\pgfplots@scale@ticks@below@exponent}%
            \ifnum\pgfplots@glob@TMPa>\pgfmathfloat@b@E
                % ok, scale it:
                \expandafter\ifx % Check whether we're using engineering notation (restricting exponents to multiples of three)
                    \csname ifpgfplots@scaled@#1@ticks@engineering\expandafter\endcsname
                    \csname iftrue\endcsname
                        \advance\pgfmathfloat@b@E by -2
                        \divide\pgfmathfloat@b@E by 3
                        \multiply\pgfmathfloat@b@E by 3
                \fi
                \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
    \fi
    \expandafter\let\csname pgfplots@tick@scale@#1\endcsname=\pgfplots@glob@TMPa%
}
\makeatother

完整代码如下:

\documentclass{article}

\usepackage{pgfplots}
\pgfplotsset{compat=newest}


\makeatletter

\newif\ifpgfplots@scaled@x@ticks@engineering
\pgfplots@scaled@x@ticks@engineeringfalse
\newif\ifpgfplots@scaled@y@ticks@engineering
\pgfplots@scaled@y@ticks@engineeringfalse
\newif\ifpgfplots@scaled@z@ticks@engineering
\pgfplots@scaled@z@ticks@engineeringfalse

\pgfplotsset{
    scaled x ticks/engineering/.code=
        \pgfplots@scaled@x@ticks@engineeringtrue,
    scaled y ticks/engineering/.code=
        \pgfplots@scaled@y@ticks@engineeringtrue,
    scaled z ticks/engineering/.code=
        \pgfplots@scaled@y@ticks@engineeringtrue,
%    scaled ticks=engineering  % Uncomment this line if you want "engineering" to be on by default
}

\def\pgfplots@init@scaled@tick@for#1{%
    \global\def\pgfplots@glob@TMPa{0}%
    \expandafter\pgfplotslistcheckempty\csname pgfplots@prepared@tick@positions@major@#1\endcsname
    \ifpgfplotslistempty
        % we have no tick labels. Omit the tick scale label as well!
    \else
    \begingroup
    \ifcase\csname pgfplots@scaled@ticks@#1@choice\endcsname\relax
    % 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
        \pgfplots@init@scaled@tick@normalize@exponents
        \ifnum\pgfmathfloat@b@E<\pgfmathfloat@a@E
            \pgfmathfloat@b@E=\pgfmathfloat@a@E
        \fi
        \xdef\pgfplots@glob@TMPa{\pgfplots@scale@ticks@above@exponent}%
        \ifnum\pgfplots@glob@TMPa<\pgfmathfloat@b@E
            % ok, scale it:
            \expandafter\ifx % Check whether we're using engineering notation (restricting exponents to multiples of three)
                \csname ifpgfplots@scaled@#1@ticks@engineering\expandafter\endcsname
                \csname iftrue\endcsname
                    \divide\pgfmathfloat@b@E by 3
                    \multiply\pgfmathfloat@b@E by 3
            \fi
            \multiply\pgfmathfloat@b@E by-1
            \xdef\pgfplots@glob@TMPa{\the\pgfmathfloat@b@E}%
        \else
            \xdef\pgfplots@glob@TMPa{\pgfplots@scale@ticks@below@exponent}%
            \ifnum\pgfplots@glob@TMPa>\pgfmathfloat@b@E
                % ok, scale it:
                \expandafter\ifx % Check whether we're using engineering notation (restricting exponents to multiples of three)
                    \csname ifpgfplots@scaled@#1@ticks@engineering\expandafter\endcsname
                    \csname iftrue\endcsname
                        \advance\pgfmathfloat@b@E by -2
                        \divide\pgfmathfloat@b@E by 3
                        \multiply\pgfmathfloat@b@E by 3
                \fi
                \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
    \fi
    \expandafter\let\csname pgfplots@tick@scale@#1\endcsname=\pgfplots@glob@TMPa%
}
\makeatother
\begin{document}
\pgfmathsetseed{1}
\begin{tikzpicture}
\begin{axis}[height=4cm, width=8cm]
\addplot {1/100000*x};
\end{axis}
\end{tikzpicture}

\end{document}

答案2

编辑2

使用此解决方案,您只需使用myaxis环境,只需在序言中输入几行即可完成工作。

\documentclass{standalone}

\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usepgflibrary{fixedpointarithmetic}
\usepackage{fp}

\makeatletter
\newcommand{\pgfplotsdrawaxis}{\pgfplots@draw@axis}
\makeatother

\pgfplotsset{after end axis/.append code={
  \pgfmathsetmacro{\maxexponent}{round(log10(\pgfkeysvalueof{/pgfplots/ymax}))}
  \pgfmathparse{-3*floor(\maxexponent/3)}
  \pgfmathsetmacro{\exponent}{\pgfmathresult}
  \def\axisdefaultticklabel{$\pgfmathprintnumber{\tick}$}
  \pgfplotsset{scaled y ticks=base 10:\exponent}
  \pgfplotsdrawaxis}}

\newenvironment{myaxis}[1][]
{\begin{axis}[scaled y ticks=false,#1]%
    \def\axisdefaultticklabel{}}
{\end{axis}}

\begin{document}

\begin{tikzpicture}[fixed point arithmetic]
\begin{myaxis}
\addplot {1000*x^2};
\end{myaxis}

\end{tikzpicture}

\end{document}

编辑1

ymax这可以完成工作,但需要在axis环境中指定

\documentclass{standalone}

\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usepgflibrary{fixedpointarithmetic}
\usepackage{fp}

\begin{document}

\begin{tikzpicture}[fixed point arithmetic]
\begin{axis}[ymax=2e7]
\pgfmathsetmacro{\maxexponent}{round(log10(\pgfkeysvalueof{/pgfplots/ymax}))}
\pgfmathparse{-3*floor(\maxexponent/3)}%
\pgfmathsetmacro{\exponent}{\pgfmathresult}
\pgfplotsset{scaled y ticks=base 10:\exponent}
\addplot {1000000*x^2};
\end{axis}
\end{tikzpicture}

\end{document}

原来的

您可以使用

scaled ticks=base 10:-9

或者单独改变xy因素scaled x ticks或者但是如果您在图中使用它则scaled y ticks必须删除该线。y tick label style={/pgf/number format/.cd,sci,precision=5}

相关内容