I'm trying to draw three "graphs" which are rectangles situated side-by-side. Each has four points to be placed on them. These four points are the "scores".

Using a foreach loop is a natural for the graphs, since all the layout and labels are the same.

What I can't figure out, is how to pass the list of data to each iteration. In other languages, I'd use something like a nested foreach, using an indirect variable whose name points to the data to plot, to place the data points. I can't seem to find variable indirection in tikz.

At present, it seems that the second \foreach is only seeing one value, rather than a list of four items. I may be using the wrong method. So other strategies welcome.

MWE:

\documentclass[]{article}
\usepackage{tikz}

\usetikzlibrary{positioning}
\usetikzlibrary{calc}

\begin{document}

% Use A4 page shape. 
% Base size of one graph is A4 page, but with pt instead of mm.

\begin{tikzpicture}

\pgfmathsetmacro{\scale}{1.75}
\pgfmathsetmacro{\graphHeight}{297 pt/\scale}   
\pgfmathsetmacro{\graphWidth}{201 pt/\scale}

\def\labelsM{85, 10, 55, 75}
\def\labelsC{75, 20, 55, 65}
\def\labelsP{65, 30, 55, 55}

\def\graphInfo{ Graph one/{(-\graphWidth pt, 0pt)}/\labelsM,
                Graph two/{(0pt, 0pt)}/\labelsC,
                Graph three/{(\graphWidth pt, 0pt)}/\labelsP
                }



\foreach \name/\pos/\values in \graphInfo
        {
    % Draw box
    \node    [
                at = {\pos},
                draw, 
                rectangle, 
                line width = 2pt,
                minimum width = \graphWidth pt,
                minimum height = \graphHeight pt,
                fill = black!15,
                name=\name
                ] 
                {} ;

    % Name graph            
    \node   [
            font = \bfseries,
            below = 2pt of \name.south
            ]
            {\name} ;   

    % Vertical lines and labels (should be 4 equidistant vertical lines) 
    \foreach \s [count=\i] in \values {
        \coordinate  (top) at  ($(\name.north west)!\i/5!(\name.north east)$) ;
        \coordinate (bottom) at ($(\name.south west)!\i/5!(\name.south east)$) ;
        \draw [dashed] (top)  --  (bottom) ;
        % Data to be plotted when this works
        };

} % end foreach \name


\end{tikzpicture}
  • I don't really get, what you are trying to achieve. Am I right, when I guess you want to set the \def\labelsM{85, 10, 55, 75} for example into the four corners of the first rectangle? – Dan H. Sep 30 '14 at 10:58
  • I just saw two typos and have updated the code. In each of the three boxes I want to plot the four values, moving from \labelsM in the first, to \labelsC in the second to \labelsP in the third. That's what I expected \values to point to in each iteration, but when the nested loop runs, it only seems to run once. – penguinpreferred Sep 30 '14 at 12:15
  • 1
    foreach doesn't expand \values completly but only one level deep. So it sees only \labelsM and not the values. Expand \values at least once before using it: \expandafter\let\expandafter\values\values – Ulrike Fischer Sep 30 '14 at 12:39
  • That worked perfectly, thanks Ulrike. However I'm having trouble understanding the command. The let replaces \values with \expandafter\values, why, though, do you then expand this also? (If I'm totally misunderstanding, please explain.) – penguinpreferred Sep 30 '14 at 21:48
  • 1
    \expandafter expands the next but one command. So the first \expandafter expands the second \expandafter which expands the second \values to \labelsX then TeX continues with the \let command. At the end you get \let\values\labelsX. – Ulrike Fischer Oct 1 '14 at 8:59
up vote 3 down vote accepted

foreach doesn't expand \values completly but only one level deep. So it sees only \labelsM and not the values. Expand \values at least once before using it:

\expandafter\let\expandafter\values\values

\expandafter expands the next but one command. So the first \expandafter expands the second \expandafter which expands the second \values to \labelsX then TeX continues with the \let command. At the end you get \let\values\labelsX.)

  • 1
    This of course assumes you know that \values expands to a single token (which is the case here). – egreg Jan 4 '15 at 11:01
  • Isn't it smpler to do \edef\values{\values} (and to have full expnsion) ? – Kpym Jan 5 '15 at 7:03
  • @Kpym: In the example that should work too. But it depends on the contents of the \labelX commands if more then one expansion is "safe". – Ulrike Fischer Jan 5 '15 at 9:00
  • @UlrikeFischer or "needed" ;) But you are right, it depends on the content of labelX if we need one, two or full expansion. – Kpym Jan 5 '15 at 9:08

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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