2

I'm attempting to create a pgfplots group plot in which each curve is made from a pre-loaded pgfplots table in an automated way. The intended application is for a complicated drawing involving many tables. The MWE below illustrates the issue. With suitable use of \expandafter (thanks to the answer to this previous question: Refer to a loaded pgfplotstable via csname), I can get a loop over multiple tables to work with \pgfplotstabletypeset. A similar loop which tries to plot both datasets fails to compile. I'd like to be able to use the unaltered \addplot syntax in such a loop. There may be a way of wrapping the invocation of \addplot in a \newcommand which could get the \expandafter trick to work, but defining a new macro for every plot I'd like to make will be inconvenient and potentially fragile. Ideally, I'd like to be able to (1) use the name passed to \pgfplotsinvokeforeach to call \addplot multiple times with different options, and (2) if possible, switch to using a numerical list, e.g., \pgfplotsinvokeforeach{0,...,5}, to implement the plotting loop.

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

2 Answers2

2

I think it's better to change syntax, so controlling expansion is easier.

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

enter image description here

egreg
  • 1,121,712
  • This works nicely for the case shown above, but it runs into problems when {} characters are used in the options that appear before the table name. For instance, \addplotnamed[sharp plot, mark=*, mark options={fill=green}] table[ x = a, y = b ] {testTable#1}; currently fails to compile. – Steven Gardiner Jul 04 '21 at 15:38
  • @StevenGardiner Can there be braces also in the [...] part after table? – egreg Jul 04 '21 at 16:13
  • Yes, I have some use cases in which this occurs. table can take the y expr option which needs braces for calling \thisrow{}, etc. – Steven Gardiner Jul 04 '21 at 16:17
  • @StevenGardiner I changed the implementation. Maybe it would be possible to keep the infix table syntax, but… – egreg Jul 04 '21 at 19:37
0

A solution that resolves item (1) but not item (2) in the question above is to create a special version of \pgfplotstablecopy. This version takes a first argument that names a loaded table macro without the leading \ character. A caveat is that using \thisrow{} within the options passed to table does not seem to work with the copied table (but does with the original).

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