2

I want to retrieve a member of a non-numeric array passed to a TikZ pic as an argument, to use it as a node label. \foreach easily does it while iterating over the array, but I cannot do it for the individual elements. The following are my two attempts that fail miserably:

\documentclass[tikz]{standalone}

\begin{document}

\tikzset{
   pics/mypic/.style n args={1}{
      code={
         \foreach \a [count=\i] in {#1}{
            \node at (\i, 1) {$\a$};
         }

         % Attempt 1: Doesn't work
         % \node at (1, 2) {$#1[0]$};

         % Attempt 2: Doesn't compile
         % Error: Undefined control sequence. ... Missing $ inserted. ...
         \node at (2, 2) {$\pgfmathparse{{#1}[0]}\pgfmathresult$};
      }
   }
}

\tikz{\pic {mypic={\mathtt{a},\mathtt{b},\mathtt{c}};}}
% \tikz{\pic {mypic={a,b,c};}}   % It's the same for this one.
% \tikz{\pic {mypic={0,1,2};}}   % Attempt 2 works with this one,
% \tikz{\pic {mypic={0,a,2};}}   % but not with this one ("Unknown function `a').

\end{document}

Output:

bad array access

I want to be able to somehow draw a node with the label #1[0]. Regarding Attempt 2, I noticed that it yields the same errors also with the text arrays. It works fine for the all-numeric arrays, but hybrid arrays are also troubling, even if the accessed element is numeric.

8
  • Try gist.github.com/moewew/2e0fcd582432a4ec72360f17085443d2. The non-numeric example entries in the array from p. 1030 are quoted with "...", and that appears to be required to avoid blow-ups (see also p. 1026). There also appeared to be a scoping issue if \pgfmathparse is used too early/too far away from \pgfmathresult. I assume that \pgfmathparse/\pgfmathresult is also used internally, so you have to be careful that your use does not get overwritten. – moewe Jul 5 '20 at 13:51
  • Incidentally the answer to tex.stackexchange.com/q/134819/35864 also works here if you make sure that you use numbers where you need them: gist.github.com/moewew/52fd825cfdd491656ab3248eda6e6f66 (the important bit is accessing the array element via evaluate=\x as \myvar using ({\radi[\x]}) and then \myvar that is unchanged). – moewe Jul 5 '20 at 13:51
  • Re \pgfmathresult being overwritten see also tex.stackexchange.com/q/497648/35864, tex.stackexchange.com/q/9988/35864, tex.stackexchange.com/q/510584/35864 – moewe Jul 5 '20 at 14:41
  • @moewe I don't like the "quotes" solution. Primarily because it requires me (and anybody else struggling at this point) to wrap their every single non-numeric array element with quotes, and they are (and might also be for anybody else) a lot at this point. It also convolutes the \foreach statement using the array. Finally, it's hard to accept that it cannot be done without the quotes, when un-quoted non-numeric elements can be captured/stored by the \foreach's iteration variable just fine. – Utkan Gezer Jul 20 '20 at 20:22
  • I may very well be wrong, but my reading of the TikZ manual is that non-numeric input in arrays is only supported if the string is wrapped in "...". I suspect some things may work without quotes, but that would be accidental and not something you can in general rely on. But I no next to nothing about TikZ so take that with a grain of salt. – moewe Jul 20 '20 at 20:24
1

Here, I use listofitems to read the desired data into an array \mydata. The OP suggested a useful EDIT to my original approach by including all of the listofitems processing inside the \tikzset code.

Note that the 2 in \mydata[2], calling out a single array element, can be any expandable calculation that results in an integer. Also, negative values denote "reverse index", that is, relative to the end of the array, rather than the beginning.

\documentclass[tikz]{standalone}
\usepackage{listofitems}

\begin{document}

\tikzset{
   pics/mypic/.style n args={1}{
      code={
         \foreach \a [count=\i] in {#1}{
            \node at (\i, 1) {$\a$};
         }

         \readlist\mydata{#1}
         \node at (2, 2) {$\mydata[2]$};
      }
   }
}

\tikz{\pic {mypic={\mathtt{a},\mathtt{b},\mathtt{c}};}}
\end{document}

enter image description here

3
  • 1
    I think it does fit! However, I don't like the idea of having to make the \readlist call each time before drawing mypic. How about making that call in the pic's code instead? That way, we also get to also keep our document just as it was. – Utkan Gezer Jul 21 '20 at 11:23
  • @UtkanGezer Thank you for your helpful edit. – Steven B. Segletes Jul 21 '20 at 11:29
  • Two valid answers within the same hour, and to a question 22 days old! I picked this one as the answer, as I will not be maintaining my hacky command in the other one, but the package listofitems sure might be. – Utkan Gezer Jul 21 '20 at 12:11
1

The following command uses \foreach to retrieve the element at a given index, and assign it globally to the given macro.

% Does #1 = #2[#3] with 0-based indexing
\newcommand\arrayget[3]{
    \foreach \a [count=\i from 0] in {#2}{
        \ifnum #3=\i
            \xdef#1{\unexpanded\expandafter{\a}}
        \fi
    }
}

References for the curious:

  • Global definition with \xdef: source 1
  • \unexpanded\expandafter{...} to expand \a once: source 2

It should be able to handle anything that \foreach can. Demonstration:

\documentclass[tikz]{standalone}

\newcommand\arrayget[3]{   % Does #1 = #2[#3] with 0-based indexing
    \foreach \a [count=\i from 0] in {#2}{
        \ifnum #3=\i
            \xdef#1{\unexpanded\expandafter{\a}}
        \fi
    }
}

\begin{document}

\tikzset{
   pics/mypic/.style n args={1}{
      code={
         \foreach \a [count=\i] in {#1}{ \node at (\i, 1) {$\a$}; }

         \arrayget{\asd}{#1}{0} \node at (1.5, 2) {$\asd$};
         \arrayget{\asd}{#1}{1} \node at (2.0, 2) {$\asd$};
         \arrayget{\qwe}{#1}{2} \node at (2.5, 2) {$\qwe$};
      }
   }
}

\tikz{\pic {mypic={\mathtt{a},\mathtt{b},\mathtt{c}};}}
\tikz{\pic {mypic={a,b,c};}}
\tikz{\pic {mypic={0,1,2};}}
\tikz{\pic {mypic={0,a,2};}}

\end{document}

Output:

Properly indexed

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.