7

I want to be able to use a macro to specify a list (it is a constant list, i.e. will not change throughout the document) and use this macro rather than hard code the list contents in the TikZ/PGFplots for readability. This problem was mentioned in this earlier question about foreach loops, but was not the main thrust of that question.

Here is a related question on how to maintain consistency with TikZ and pgfplots, and its continuation on the use of a macro as coordinate in pgfplots, but these related to specifying coordinates, and not lists.

In the MWE below, Example 1's solution is based on this question on using a macro defined list in a foreach which suggested to not enclose the macro defined list in a curly brace. This works fine for TikZ, so no problem yet.

However, in PGFplots things are different. The solution in Example 2 to using a foreach is from the above referenced question, and works great as long as I do not use a macro for the list, but I would prefer to use a macro here.

In Example 3, I can easily use a macro defined list for the xtick, but am not able use it for xticklabels.

So, is there a consistent way that I can always define a macro for a list and then use it without having to worry about the context of its use? If not, is there a way to change the definition of the list and/or its use for Examples 2 and 3 that work in those situations.

\documentclass{article}
\usepackage{pgfplots}

\newcommand*{\XTickLocationList}{-2, -1, 1, 2}
\newcommand*{\XTickLabelsList}{a, b, c, d}
\newcommand*{\XTickLocationsAndLabels}{-2/a, -1/b, 1/c, 2/d}

\begin{document}
\begin{tikzpicture}   % Example 1
\draw [->][gray, thin](-3,0) -- (3,0) node[blue, right] {$x$}; 
\draw [->][gray, thin](0,-3) -- (0,3) node[blue, above] {$y$};

%\foreach \x/\l in {-2/a, -1/b, 1/c, 2/d} { % Works
%\foreach \x/\l in {\XTickLocationsAndLabels} {  % Does not compile
\foreach \x/\l in \XTickLocationsAndLabels {  % Works
    \draw [thick, red]
        (\x,-2pt) -- (\x,2pt)
        node [red, above] {\l};
}
\end{tikzpicture}

\begin{tikzpicture}   % Example 2
\begin{axis}[
    minor tick num=0, 
    axis y line=center, 
    axis x line=middle, 
    xmin=-3, xmax=3, 
    ymin=-3, ymax=3,
    xlabel=$x$, ylabel=$y$,
    xtick={0},  xticklabels={}
    ]

\foreach \x/\l in {-2/a, -1/b, 1/c, 2/d}{ % Works
%\foreach \x/\l {\XTickLocationsAndLabels}  % Does not compile
%\foreach \x/\l \XTickLocationsAndLabels  % Does not compile
    \edef\temp{\noexpand\addplot
        [mark=none,color=red, thin, samples=2]%
        coordinates{ (\x,-0.05) (\x,0.05) }
            node [red, below] {\l};
    }
    \temp
} 

\end{axis}
\end{tikzpicture}

\begin{tikzpicture}    % Example 3
\begin{axis}[
    minor tick num=0, 
    axis y line=center, 
    axis x line=middle, 
    xmin=-3, xmax=3, 
    ymin=-3, ymax=3,
    xlabel=$x$, ylabel=$y$,
    %xtick={-2, -1, 1, 2}, % Works
    %xtick=\XTickLocationList, % Works
    xtick={\XTickLocationList}, % Works
    xticklabels={a, b, c, d}  % Works
    %xticklabels={\XTickLabelsList}  % Compiles, but wrong results
    %xticklabels=\XTickLabelsList  % Compiles, but wrong results
    ]

\end{axis}
\end{tikzpicture}
\end{document}
4
  • Knowing that this comment is not really what you asked for, I still want to mention one possible approach: did you consider using a style instead of \XTickLabelsList? For example \pgfplotsset{x tick labels list/.style={xticklabels={a,b,c,d}} will allow you to write x tick labels list whenever you want that macro. Concerning the original question: I can investigate why the list is expanded for xtick but not for xticklabels. Perhaps this should be unified. May 10, 2011 at 20:54
  • @Christian: Small typo in your solution: Need three } at end. With that fix, this would be fine if I could say \pgfplotsset{x tick labels list/.style={xticklabels={\XTickLabelsList}}}. So, that the list is only defined once and can be accessed in the \begin{axis} environment as x tick labels list and as \XTickLabelsList within a foreach. May 10, 2011 at 22:18
  • I see. I fear you stumbled over an issue in pgfplots which causes the construction xticklabels={\macro} to be treated in a different way than in \foreach. I'll take a note in the pgfplots todo list. But that means you may want to use a different solution until a solution has been found and released. May 13, 2011 at 19:56
  • I also provided an alternative answer to tex.stackexchange.com/questions/15684/… May 13, 2011 at 20:31

1 Answer 1

11

Given the restrictions discussed in my comments above, I suggest using a more technical approach - which is absolutely reliably and fully portable (but less commonly known in LaTeX).

I mean, the problem is that pgfplots does not understand xticklabels={\XTickLabelsList}. More precisely: it takes the argument as (single) list entry rather than expanding it. To be honest, I am not even sure if someone might want to use such a feature (a one-element-list witch a macro as content).

So, what we need is to provide the content of \XtickLabelsList programmatically.

Well, here is the promised solution:


\edef\temp{%
  \noexpand\pgfplotsset{%
      x tick labels list/.style={xticklabels={\XTickLabelsList}}
  }%
}
\temp
It defines \temp to contain the "fully expanded" content of the argument in braces ("e"xpanded "def"inition). If a \noexpand occurs in the argument of \edef, the "fully expanded" content of the item following \noexpand is the item itsself, i.e. \noexpand\pgfplotsset stays \pgfplotsset. But \XTickLabelsList will be replaced by its content. Note that any macro which might occur in \XTicjLabelsList might also be expanded (there are other techniques to avoid that. In case you need them, pose the question again or research in my TeX-programming-notes.pdf which should be shipped with pgfplots).

Anyway, the \temp macro will finally contain \pgfplotsset{.....{a,b,c,d}}} (type \show\temp to verify it). Executing \temp will activate the changes and you can readily use the style afterwards with x tick labels list.

5
  • This new suggestion does not quite work for me. If I use the above \edef, and have xticklabels={\XTickLabelsList} in the \begin{axis} I get one label a,b,c,d as I was without the \edef. If I remove the statement form the \begin{axis}, the points get labelled with their numerical values, not the alpha list that I specified. Perhaps I am not using it properly. May 20, 2011 at 0:41
  • @Peter Sorry, I fear one point got lost on my lengthy explanation: the solution above does only work if you provide the \edef in your preamble and use x tick labels list instead of xticklabels={\XTickLabelsList} in your axes. May 20, 2011 at 18:10
  • At least 10 people would like such a feature.
    – u17
    Mar 24, 2018 at 9:40
  • Thanks for the input, @ Frank! In the meantime, a related feature has been added to pgfkeys in general: one can write xticklabels/.expand once={\XTickLabelsList} with the desired effect and without the technical overhead in my example. Would that address the use-case? Mar 30, 2018 at 7:44
  • 1
    @ChristianFeuersänger: The .expand once seems to work well for me. Much cleaner than the above \edef solution. Apr 10, 2018 at 8:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .