4

I am struggling with following fairly simple looking problem of plotting a family of curves.

\documentclass[border=1mm]{standalone}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.8}

\pgfplotstableread{
1   1
2   4
3   9
4   16
5   25
}\dataQuad

\begin{document}
\begin{tikzpicture}
\begin{axis}[%
    legend pos=north west,
    domain=0:5,
    xlabel=${x}$,
    ylabel=${y}$]
    \foreach \y/\c in {2/black,3/green,4/red,5/brown}{%
        \edef\temp{\noexpand\addplot[color=\c,line width=1pt] {x^\y};}
        \temp
        \addlegendentryexpanded{$y=x^\y$}
    }
\end{axis}
\end{tikzpicture}

\begin{tikzpicture}
\begin{axis}[%
    legend pos=north west,
    domain=0:5,
    cycle list name=color,
    xlabel=${x}$,
    ylabel=${y}$]
    \addplot [smooth] table[x index=0, y index=1] {\dataQuad};
    \legend{$y=x^2$}
    \foreach \y in {3, 4, 5} {%
%       \foreach \y/\c in {3/green,4/red,5/brown}{%
        \addplot [smooth] table[x index=0, y expr=\thisrowno{0}^\y] {\dataQuad};
%           \edef\temp{\noexpand\addplot [smooth] table[x index=0, y expr=\thisrowno{0}^\y] {\dataQuad};}
%           \temp
        \addlegendentryexpanded{$y=x^\y$}
    }   
\end{axis}
\end{tikzpicture}
\end{document}

I'd like to have the same result shown on the left when using a table with some math expressions. One problem is to handle the color management when uncomment the lines within second tikzpicture (by changing the foreach-loop). I can't get it to work. Seems to be a problem with expansion.

Any advice is much appreciated!

Thanks Paul

Paul
  • 325
  • 2
  • 7

2 Answers2

4

For applications like this, PGFPlots provides its own looping macro that expands and executes the plot commands at the right time:

\pgfplotsinvokeforeach{<list>}{ <code, with #1 the current list value> }

\documentclass[border=1mm]{standalone}
\usepackage{pgfplots, pgfplotstable}
\pgfplotsset{compat=1.8}

\pgfplotstableread{
1   1
2   4
3   9
4   16
5   25
}\dataQuad

\begin{document}
\begin{tikzpicture}
\begin{axis}[%
    legend pos=north west,
    domain=0:5,
    cycle list={black, green, red, brown},
    xlabel=${x}$,
    ylabel=${y}$
    ]
    \pgfplotsinvokeforeach{2, 3, 4, 5}{%
        \addplot +[smooth, thick] table[x index=0, y expr=\thisrowno{0}^#1] {\dataQuad};
        \addlegendentryexpanded{$y=x^#1$}
    }   
\end{axis}
\end{tikzpicture}
\end{document}
Jake
  • 232,450
4

EDIT: this here explains what went wrong in your case. However, Jake's approach constitutes a best-practice: it relies on cycle list which simplifies style (color) management and avoids the issue altogether.


The complicated structure with \edef is incomplete; it is an expansion issue (as you suspected).

The problem is that \edef (Expanded DEFinition) attempts to expand every encountered macro. In your case, you ONLY want to expand \y and \c. Consequently, you have to protect every other encountered macro. In your case, the protection is missing for \thisrowno and \dataQuad. The "protection" is done by prefixing the macros-to-protect by \noexpand.

Taking it together, one arrives at

\documentclass[border=1mm]{standalone}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.8}

\pgfplotstableread{
1   1
2   4
3   9
4   16
5   25
}\dataQuad

\begin{document}
\begin{tikzpicture}
\begin{axis}[%
    legend pos=north west,
    domain=0:5,
    xlabel=${x}$,
    ylabel=${y}$]
    \foreach \y/\c in {2/black,3/green,4/red,5/brown}{%
        \edef\temp{\noexpand\addplot[color=\c,line width=1pt] {x^\y};}
        \temp
        \addlegendentryexpanded{$y=x^\y$}
    }
\end{axis}
\end{tikzpicture}

\begin{tikzpicture}
\begin{axis}[%
    legend pos=north west,
    domain=0:5,
    cycle list name=color,
    xlabel=${x}$,
    ylabel=${y}$]
    \addplot [smooth] table[x index=0, y index=1] {\dataQuad};
    \legend{$y=x^2$}
    \foreach \y/\c in {3/green,4/red,5/brown}{%
         \edef\temp{\noexpand\addplot [color=\c,smooth] table[x index=0, y expr=\noexpand\thisrowno{0}^\y] {\noexpand\dataQuad};}
         \temp
        \addlegendentryexpanded{$y=x^\y$}
    }   
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

  • @Jake It is good to notice that the number of list entries in 'cycle list' do not necessarily need to match the number of loop entries. – Paul Jul 30 '13 at 22:15