自定义单位显示位置

自定义单位显示位置

如何调整 的位置y unitpgfplots我试图将其放在图形框的左上角附近。但是,可能(但不必)是科学乘数。如下面的专业排版图片所示,单位应显示在乘数之后,当然应与乘数对齐,就像写成一个整体一样:$10^3$[m]。如果y轴上的值较小且未显示指数符号,[m]则单位仍应呈现在左上角上方,但最好靠近左边缘。

输出图

我知道[m]图片中的单位是与y轴标签一起绘制的。我不需要将整数放在y label乘数附近,而只需放置单位即可。事实上,我根本不需要轴标签。是否可以控制科学乘数的格式并附加单位?

我不确定这是否重要,但为了完整起见,让我补充一下,我已经结合了 Jake 的刻度缩放解决方案这里只有指数,即 3 的倍数。

MWE 提供:

\documentclass{minimal}
\usepackage{pgfplots}
\usepgfplotslibrary{units}

\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}
    \begin{tikzpicture}
        \begin{axis}[scaled ticks=engineering, y unit=m,height=4cm]
        \addplot [domain=0:1] {10000*\x};
        \end{axis}
    \end{tikzpicture}

    The multiplier should be printed as $\cdot10^3$[m] instead of merely $\cdot10^3$.
\end{document}

答案1

这是一种不使用units库的方法,而是定义一个新键y unit label=<text>,将其放置<text>在刻度标签后面(如果存在)或刻度标签的位置(如果不存在)。

如果您将以下代码放在序言中...

\makeatletter
\long\def\ifnodedefined#1#2#3{%
    \@ifundefined{pgf@sh@ns@#1}{#3}{#2}%
}

\pgfplotsset{
    y unit label/.style={
        y tick scale label style={
            name=y tick scale label,
            inner xsep=0pt
        },
        after end axis/.append code={
            \ifnodedefined{y tick scale label}{%
                \tikzset{
                    every y unit label/.append style={
                        anchor=base west, at=(y tick scale label.base east)
                    }
                }
            }{%
                \tikzset{
                    every y unit label/.append style={
                        /pgfplots/every y tick scale label
                    }
                }
            }
            \node [every y unit label] {#1};
        }
    }
}
\makeatother

...您可以编写以下内容...

\begin{axis}[
        scaled ticks=engineering,
        y unit label=m,
        height=4cm,
        ]
\addplot [domain=0:1] {10000*\x};
\end{axis}

... 要得到 ...

... 或者 ...

\begin{axis}[
        scaled ticks=engineering,
        y unit label=m,
        height=4cm,
        ]
\addplot [domain=0:1] {10000*\x};
\end{axis}

... 要得到 ...


完整代码:

\documentclass{article}
\usepackage{pgfplots}

\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


\makeatletter
\long\def\ifnodedefined#1#2#3{%
    \@ifundefined{pgf@sh@ns@#1}{#3}{#2}%
}

\pgfplotsset{
    y unit label/.style={
        y tick scale label style={
            name=y tick scale label,
            inner xsep=0pt
        },
        after end axis/.append code={
            \ifnodedefined{y tick scale label}{%
                \tikzset{
                    every y unit label/.append style={
                        anchor=base west, at=(y tick scale label.base east)
                    }
                }
            }{%
                \tikzset{
                    every y unit label/.append style={
                        /pgfplots/every y tick scale label
                    }
                }
            }
            \node [every y unit label] {#1};
        }
    }
}
\makeatother


\pgfplotsset{compat=1.8}
\begin{document}
    \begin{tikzpicture}
        \begin{axis}[
                scaled ticks=engineering,
                y unit label=m,
                height=4cm,
                ]
        \addplot [domain=0:1] {10*\x};
        \end{axis}
    \end{tikzpicture}

\end{document}

答案2

这不是一种通用方法,而是在没有其他解决方案的情况下的权宜之计。在这种情况下,关闭 y 轴标签,并在指定位置用所需文本覆盖图像。与您的 MWE 相关的更改的相关行如下:

\usepackage{stackengine}
\def\stackalignment{l}
\begin{document}
\topinset{[m]}{%
    \begin{tikzpicture}
        \begin{axis}[scaled ticks=engineering, height=4cm]
        \addplot [domain=0:1] {10000*\x};
        \end{axis}
    \end{tikzpicture}%
}{.03in}{.8in}

在此处输入图片描述

相关内容