TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm using a macro that uses \StrBetween from xstring

It seems to be working great.

However, when I try to use a value that it returns as a coordinate in a tikz picture, I get a confusing error.

Consider this snippet:

\documentclass[letterpaper,12pt]{article}

\usepackage{xstring}
\usepackage{tikz}

% http://tex.stackexchange.com/a/21566/3068
\newcommand*\GetListMember[2]{\StrBetween[#2,\number\numexpr#2+1]{,#1,},,\par}%

\begin{document}
\pagestyle{empty}
\begin{tikzpicture}
\def\A{\GetListMember{1,2,3}{1}}

% This makes me think the value of \A is 1
\node [draw] at (1,0) {\A};

% Uncommenting the following gives an error that is very confusing to me
% \node [draw] at (\A,1) {\A};
\end{tikzpicture}
\end{document}

It works, but if I uncomment the last commented line, I get this error:

! Undefined control sequence.
<argument> \@@cls 

l.18 \node [draw] at (\A,1)
                            {\A};

I think I need to convert the value of \A to a number, or something, but I don't know how.

p.s. This happens a lot, where an error message contains text that's not in my input file. (In this case \@@cls) Is there a way for me to see the intermediate forms? I feel like I'm debugging Lisp code with no macroexpand-1.

Thanks, as ever. (:

share|improve this question
up vote 10 down vote accepted

You haven't defined \A to be 1 you've defined it to be \GetListMember{1,2,3}{1} (you get 1 when \A is expanded). TikZ has no idea what to do with \GetListMember when it encounters it in a coordinate. In this case you can use \pgfmathtruncatemacro. To see the difference consider the following (for clarity I've used \A and \B):

\documentclass{article}
\usepackage{xstring}
\usepackage{tikz}

\begin{document}
\def\A{\GetListMember{1,2,3}{1}}
\show\A
\pgfmathtruncatemacro\B{{1,2,3}[0]}
\show\B
\end{document}

When you look at the log file you should see:

> \A=macro:
->\GetListMember {1,2,3}{1}.
l.7 \show\A
> \B=macro:
->1.
l.9 \show\B 
share|improve this answer
1  
Thanks for this answer, I always learn so much when I post a question here. I have a vague memory of learning about \show in the past, but it didn't occur to me that it might be useful for this type of debugging. – Harold Mar 8 '13 at 13:39
    
How would I do the exact same thing, but with a list variable and counter? I have some list variable \mylist, and a counter \i in a foreach loop, but just writing \pgfmathtruncatemacro\B{\mylist}[\i]} fails .... – Gandalf Lechner Apr 19 at 8:01

Your problem is expansion. The line

\def\A{\GetListMember{1,2,3}{1}}

defines \A to be \GetListMember{1,2,3}{1}, which is clearly not a number. TeX tries to expand this as part of the internals of \node, but \StrBetween is not 'expandable. You can see that if you try to force expansion using \edef:

\edef\A{\GetListMember{1,2,3}{1}}

which will also give the same error.

What you need is an expandable comma-list item selector. The xstring package does not provide one, but expl3 does:

\documentclass[letterpaper,12pt]{article}

\usepackage{expl3}
\usepackage{tikz}

\begin{document}
\pagestyle{empty}
\begin{tikzpicture}
\ExplSyntaxOn
\edef\A{\clist_item:nn{1,2,3}{1}}
\ExplSyntaxOff

\node [draw] at (1,0) {\A};
\node [draw] at (\A,1) {\A};
\end{tikzpicture}
\end{document}

Probably you'll want to wrap up \clist_item:nn in a user-level macro.

share|improve this answer
    
I appreciate this answer, I was unaware of expl3 – Harold Mar 8 '13 at 13:35

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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