如何根据 pgfplots 中给定列表的计算创建列表刻度?

如何根据 pgfplots 中给定列表的计算创建列表刻度?

我想创建 x 轴和 y 轴上的刻度列表。我从这篇文章中注意到了一种生成新列表的方法[如何在 pgfplots 中的 tick 定义中使用宏]

我将该代码修改为以下 MWE。在我的代码中,我想基于列表创建两个刻度列表{0.75,3.5,1.0,1.5,1.0,3.5,1.0,1.5}。第一个列表只是按顺序将这些值相加。第二个列表是将第一个列表的值加倍。然后,将新生成的列表用作轴的刻度。

\documentclass{article}
\usepackage{tikz}

%% Example code copied from another post.
\newcommand{\deflisttickold}[1]{
\gdef\listticksold{}% global list
\foreach \x[count=\xi] in {#1}{\global\let\maxitems\xi}% count the max number of items
\show \maxitems
\foreach \x[count=\xi] in {#1}{
    \ifnum\xi=\maxitems
        \xdef\listticksold{\listticks \x}
    \else
        \xdef\listticksold{\listticks \x,}
    \fi
    }
}

%% New code modified from \deflisttickold
\newcommand{\deflistticknewone}[1]{
\gdef\listticksnewone{}% global list
\pgfmathsetmacro{\currval}{0.0}
\foreach \x[count=\xi] in {#1}{\global\let\maxitems\xi}% count the max number of items
\foreach \x[count=\xi] in {#1}{
    \pgfmathparse{\currval+\x}
    \global\edef\currval{\pgfmathresult}
    \ifnum\xi=\maxitems
        \xdef\listticksnewone{\listticksnewone \currval}
    \else
        \xdef\listticksnewone{\listticksnewone \currval,}
    \fi
    }
}

\newcommand{\deflistticknewtwo}[1]{
\gdef\listticksnewtwo{}% global list
\pgfmathsetmacro{\lastval}{0.0}
\foreach \x[count=\xi] in {#1}{\global\let\maxitems\xi}% count the max number of items
\foreach \x[count=\xi] in {#1}{
    \pgfmathparse{2.0*(\x-\lastval)}
    \global\edef\lastval{\x}
    \ifnum\xi=\maxitems
        \xdef\listticksnewtwo{\listticksnewtwo \pgfmathresult}
    \else
        \xdef\listticksnewtwo{\listticksnewtwo \pgfmathresult,}
    \fi
    }
}

\edef\mylist{0.75,3.5,1.0,1.5,1.0,3.5,1.0,1.5}
\deflisttickold{\mylist}
\deflistticknewone{\mylist}
\deflistticknewtwo{\listticksnewone}

\begin{tikzpicture}
    \begin{axis}[
        xmode=linear,
        ymode=linear,
        axis x line*=bottom,
        axis y line*=left,
        tick label style={font=\small},
        grid=both,
        tick align=outside, 
        tickpos=left,
        width=0.65\textwidth,
        height=0.4\textwidth,
        xmin=0,
        xtick = \listticksnewone,
        xticklabels = \listticksnewone,
        ytick = \listticksnewtwo,
        yticklabels = \listticksnewtwo,
    ]

    \addplot coordinates {
        (0.25, 2.5)
        (1.5, 3)
        (3.5, 3.5)
        (5, 4.5)
        (7, 5)
    };

    \end{axis}
\end{tikzpicture}

\end{document}

但是,我的代码运行得不太好。如果我使用给定的代码复制列表,则新生成的列表\deflisttickold{\mylist}确实是列表。\deflistticknewone{\mylist}和生成的列表\deflistticknewtwo{\listticksnewone}是不正确的。

有人能帮我找出问题吗?提前谢谢了。

答案1

一种方法是采用在 TikZ/PGFplots 中使用宏定义列表并定义一种x tick labels list风格:

\edef\temp{\noexpand\pgfplotsset{x tick labels list/.style={xticklabels={\MyDoubleList}}}}
\temp

新的列表在哪里\MyDoubleList,然后将其作为选项应用于环境axis

要根据旧列表创建新列表,请执行以下操作:

  1. 定义一个宏,返回根据给定值计算出的新值。例如:

    \newcommand*{\MultiplyByTwo}[1]{2*#1}%
    

    将使提供的价值加倍。

  2. 调用\DefineNewList宏并传入

        % #1 = macro to contain new list
        % #2 = function which evaluates new list member based on old list member
        % #3 = old list
    

    因此,如果\mylist包含您的原始列表,则调用

    \DefineNewList{\MyDoubleList}{\MultiplyByTwo}{\mylist}
    

    创建一个列表\MyDoubleList,其中每个元素都是 中的值的两倍\mylist

将它们放在一起会在 x 轴上产生标签,0.5, 2.0, 4.0其值为实际值的两倍:

在此处输入图片描述

代码:

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.13}


\makeatletter
\newcommand*{\@tempDefineNewList}{}% Ensure it is not already defined
\newcommand*{\DefineNewList}[3]{%
    % #1 = macro to contain new list
    % #2 = function which evaluates new list member based on old list member
    % #3 = old list
    \gdef#1{}% Initialize
    \edef\expandedOldList{#3}%
    \foreach [count=\xi] \x in \expandedOldList {%
        \pgfmathsetmacro{\@tempDefineNewList}{#2{\x}}%
        \ifnum\xi=1\relax
            \xdef#1{\@tempDefineNewList}%
        \else
            \xdef#1{#1, \@tempDefineNewList}%
        \fi
    }%
}%
\makeatother

\newcommand*{\MultiplyByTwo}[1]{2*#1}%
\newcommand*{\MultiplyByThree}[1]{2*#1}%
\newcommand\mylist{0.5, 2.0, 4.0}

\DefineNewList{\MyDoubleList}{\MultiplyByTwo}{\mylist}
\DefineNewList{\MyTripleList}{\MultiplyByThree}{\mylist}

%% https://tex.stackexchange.com/questions/17833/using-macro-defined-lists-in-tikz-pgfplots
\edef\temp{\noexpand\pgfplotsset{x tick labels list/.style={xticklabels={\MyDoubleList}}}}%
\temp

\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        xmode=linear,
        ymode=linear,
        axis x line*=bottom,
        axis y line*=left,
        tick label style={font=\small},
        grid=both,
        tick align=outside, 
        tickpos=left,
        width=0.65\textwidth,
        height=0.4\textwidth,
        xmin=0,
        xtick=\mylist,
        x tick labels list,% <-- see effect of commenting this out.
    ]

    \addplot coordinates {
        (0.25, 2.5)
        (1.5, 3)
        (3.5, 3.5)
        (5, 4.5)
        (7, 5)
    };

    \end{axis}
\end{tikzpicture}

答案2

我找到了我的问题的答案。

代码段如下。

\newcommand{\deflisttick}[1]{
\gdef\listticks{}% global list
\pgfmathsetmacro{\currval}{0.0}
\foreach \x [count=\xi] in #1 {\global\edef\maxitems{\xi}}% count the max number of items
\foreach \x [count=\xi] in #1 {
    \pgfmathparse{\currval+\x}
    \global\edef\currval{\pgfmathresult}
    \ifnum\xi=\maxitems
        \global\edef\listticks{\listticks \currval}
    \else
        \global\edef\listticks{\listticks \currval,}
    \fi
    }
}

\edef\mylist{0.75,3.5,1.0,1.5,1.0,3.5,1.0,1.5}
\deflisttick{\mylist}

\begin{tikzpicture}
    \begin{axis}[
        xmode=linear,
        ymode=linear,
        axis x line*=bottom,
        axis y line*=left,
        tick label style={font=\small},
        grid=both,
        tick align=outside, 
        tickpos=left,
        width=0.65\textwidth,
        height=0.4\textwidth,
        xmin=0, xmax=15,
        xtick = \listticks,
    ]

    \addplot coordinates {
        (0.25, 2.5)
        (1.5, 3)
        (3.5, 3.5)
        (5, 4.5)
        (7, 5)
    };

    \end{axis}
\end{tikzpicture}

创建一个新列表作为给定列表的部分和。部分和列表用作 xticks 列表。此代码段将生成如图所示的图形。在此处输入图片描述

相关内容