3

I'm trying to produce a boxplot with pgfplots where the data plotted is produced by some other command. Here a MCVE:

\documentclass{article}
 \usepackage{pgfplots}
 \pgfplotsset{compat=1.13}
 \usetikzlibrary{pgfplots.statistics}

 \newcommand{\addBoxplot}[1]{%
  \begin{tikzpicture}%
   \begin{axis}%
    \addplot[boxplot = {average = auto}] table[row sep=\\,y index=0] {#1};%
   \end{axis}%
  \end{tikzpicture}%
 }

 \newcommand{\getData}{data\\ 1\\ 3\\}

\begin{document}
 % Try 1
 \addBoxplot{data\\ 1\\ 3\\ }

 % Try 2
 \addBoxplot{\getData}
\end{document}

Try 1 demonstrates that the \addBoxplot command works as expected. Try 2 is the case I really am interested in. This produces an empty boxplot instead of giving just the same plot as try 1. Here is the output for me:

Output for me

The problem seems to be that the \getData is evaluated too late which causes \addBoxplot to produce the plot from invalid / empty data.

How can I implement \addBoxplot to work in context of try 2?

2

\expandafter can be your best friend (or your worst nightmare).

In this case, \addBoxplot doesn't want to see a macro name, it wants to see actual data, so the macro \getdata must be expanded once to so that \addBoxplot sees the argument in the form it likes.

\documentclass{article}
 \usepackage{pgfplots}
 \pgfplotsset{compat=1.13}
 \usetikzlibrary{pgfplots.statistics}

 \newcommand{\addBoxplot}[1]{%
  \begin{tikzpicture}%
   \begin{axis}%
    \addplot[boxplot = {average = auto}] table[row sep=\\,y index=0] {#1};%
   \end{axis}%
  \end{tikzpicture}%
 }

 \newcommand{\getData}{data\\ 1\\ 3\\}

\begin{document}
 % Try 1
 \addBoxplot{data\\ 1\\ 3\\ }

 % Try 2
 \expandafter\addBoxplot\expandafter{\getData}
\end{document}

enter image description here

  • Woohoo! This is the solution. Could you elaborate the mystery? I have tried \expandafter-variants before. Why do I need two of those? – m8mble May 17 '17 at 12:51
  • I am also curious, I was trying the same, but I thought \expandafter would expand the second token encountered? – Pietro Saccardi May 17 '17 at 12:52
  • @m8mble Think of it like reading left to right, this is the manner in which TeX digests the input. When getting to the 1st \expandafter, it momentarily skips \addBoxplot, and expands the 2nd instance of \expandafter, which says to skip the { and expand \getdata once. Having performed that much, it goes back and finds \addBoxPlot{data\\ 1\\ 3\\}. – Steven B. Segletes May 17 '17 at 12:54
  • @PietroSaccardi See my prior comment. It gets really tricky if you want to expand something twice rather than once. Then you need groups of 3 \expandafters, as in \expandafter\expandafter\expandafter\addBoxplot\expandafter\expandafter\expandafter{\getData}. Can you see why? The 1st, 3rd, 4th, 6th instances will expand \getdata the 1st time, and then the 2nd,5th instances will expand it the 2nd time. Three expansions require 7 successive \expandafters using the same logic. – Steven B. Segletes May 17 '17 at 12:58
  • 1
    @PietroSaccardi More specifically to your point, "I thought \expandafter would expand the second token encountered", the second token encountered is the {, not the \getData. – Steven B. Segletes May 17 '17 at 13:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.