使用 \csname 和 \addplot 迭代已加载的 pgfplots 表

使用 \csname 和 \addplot 迭代已加载的 pgfplots 表

我正在尝试创建一个 pgfplots 组图,其中每条曲线都是以自动方式从预加载的 pgfplots 表生成的。预期应用是用于涉及许多表的复杂绘图。下面的 MWE 说明了这个问题。适当使用\expandafter(感谢上一个问题的答案:通过 csname 引用已加载的 pgfplotstable),我可以对多个表进行循环以使用\pgfplotstabletypeset。尝试绘制两个数据集的类似循环无法编译。我希望能够\addplot在这样的循环中使用未改变的语法。可能有一种方法可以将调用包装\addplot在中\newcommand,这可以使\expandafter技巧奏效,但为每个我想要绘制的图定义一个新宏会很不方便,而且可能很脆弱。理想情况下,我希望能够 (1) 使用传递给的名称以不同的选项多次\pgfplotsinvokeforeach调用\addplot,以及 (2) 如果可能,切换到使用数字列表(例如\pgfplotsinvokeforeach{0,...,5})来实现绘图循环。

\documentclass{standalone}

\usepackage{pgfplots}
\usetikzlibrary{pgfplots.groupplots}
\usepackage{pgfplotstable}

\begin{document}

\pgfplotstableread{
  a  b
  1  4
  2  5
  3  6
}{\testTableOne}

\pgfplotstableread{
  a  b
  1  2
  2  3
  3  4
}{\testTableTwo}

\pgfplotsinvokeforeach{One,Two}{%
  \expandafter\pgfplotstabletypeset\expandafter{\csname testTable#1\endcsname}
}

\begin{tikzpicture}
  \begin{groupplot}[group style = {group size = 1 by 2}]

\pgfplotsinvokeforeach{One,Two}{
  \nextgroupplot
  \addplot table[ x = a, y = b ]
    % This fails to compile
    {\csname testTable#1\endcsname};
    % This works, but doesn't vary the plot
    %{\testTableOne};
}
  \end{groupplot}
\end{tikzpicture}

\end{document}

答案1

我认为最好改变语法,这样控制扩展就更容易了。

\documentclass{article}

\usepackage{pgfplots}
\usetikzlibrary{pgfplots.groupplots}
\usepackage{pgfplotstable}

\ExplSyntaxOn
\NewDocumentCommand{\addplotnamedtable}{oO{}m}{%
  \IfNoValueTF{#1}
   {% the call is like \addplot table[...}{...}
    \use:e { \exp_not:n { \addplot table~[#2] } { \exp_not:c { #3 } } }
   }
   {% the call is like \addplot [...] table [...] {...}
    \use:e { \exp_not:n { \addplot [#1]~table~[#2] } { \exp_not:c { #3 } } }
   }
 }
\ExplSyntaxOff

\begin{document}

\pgfplotstableread{
  a  b
  1  4
  2  5
  3  6
}{\testTableOne}

\pgfplotstableread{
  a  b
  1  2
  2  3
  3  4
}{\testTableTwo}

\pgfplotsinvokeforeach{One,Two}{%
  \expandafter\pgfplotstabletypeset\expandafter{\csname testTable#1\endcsname}
}

\begin{tikzpicture}
  \begin{groupplot}[group style = {group size = 1 by 2}]

\pgfplotsinvokeforeach{One,Two}{
  \nextgroupplot
  \addplotnamedtable [sharp plot, mark=*, mark options={fill=green}][x = a, y = b ] {testTable#1};
}
  \end{groupplot}
\end{tikzpicture}

\end{document}

在此处输入图片描述

答案2

解决上述问题中的第 (1) 项但不能解决第 (2) 项的解决方案是创建一个特殊版本\pgfplotstablecopy。此版本采用第一个参数,该参数命名加载的表宏而不带前导\字符。需要注意的是,\thisrow{}在传递给的选项中使用table似乎不适用于复制的表(但适用于原始表)。

\documentclass{standalone}

\usepackage{pgfplots}
\usepgfplotslibrary{groupplots}
\usepackage{pgfplotstable}

\begin{document}

\pgfplotstableread{
  a  b
  1  4
  2  5
  3  6
}{\testTableOne}

\pgfplotstableread{
  a  b
  1  2
  2  3
  3  4
}{\testTableTwo}

% Define the \backslashchar macro to be a \ character with a normal catcode.
% See https://tex.stackexchange.com/a/7372/61460 for an explanation. We will
% use this character below to trick pgfplotstable into allowing us to copying
% from a loaded table without using a leading \ in the name.
\begingroup\lccode`!=`\\\lowercase{\endgroup\def\backslashchar{!}}

% Make a special version of the macro \pgfplotstablecopy. This version copies
% from a loaded table specified as the first argument without a leading \.
\makeatletter
\newcommand{\Specialpgfplotstablecopy}[2]{%
  \edef#2{\expandafter\noexpand\csname #1\endcsname}%
  \expandafter\let\expandafter\pgfplotstable@loc@TMPa%
    \csname\backslashchar\string#1@@table@name\endcsname
  \expandafter\let\csname\string#2@@table@name\endcsname=\pgfplotstable@loc@TMPa
  \expandafter\edef\csname\string#2@@table@scanline\endcsname{\csname\backslashchar\string#1@@table@scanline\endcsname}%
  \expandafter\pgfplotslistforeachungrouped\csname#1\endcsname\as\pgfplotstable@loc@TMPa{%
    \def\pgfplotstable@loc@TMPb{%
      \expandafter\let\csname\string#2@\pgfplotstable@loc@TMPa\endcsname}%
    \expandafter\pgfplotstable@loc@TMPb\csname\backslashchar\string#1@\pgfplotstable@loc@TMPa\endcsname
  }%
}
\makeatother

\begin{tikzpicture}
  \begin{groupplot}[group style = {group size = 1 by 2}]

    \pgfplotsinvokeforeach{One,Two}{
      \nextgroupplot
      \Specialpgfplotstablecopy{testTable#1}{\tempTable};
      \addplot[sharp plot, mark=*, mark options={fill=green}]
        table[ x = a, y = b ] {\tempTable};
      % Breaks due to the \thisrow{} expression.
      % It works for the original table.
      %\addplot[sharp plot, mark=*, mark options={fill=green}]
      %  table[ x = a, y expr = \thisrow{b} ] {\tempTable};
    }

  \end{groupplot}
\end{tikzpicture}

\end{document}

相关内容