Take the 2-minute tour ×
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.

Motivation

As stated in the title, I'm trying to define a command able, from a list of colors as input, to create a list in which colors are numbered. This, manually, has been done in Arrows coordinates in TikZ

Preliminary work

I've tried to search in the site questions related to the problem, such as How to define macros in a foreach loop with effects between iterations and after the loop without using global?, How to define macros in a foreach loop with effects between iterations and after the loop without using global? (especially solutions shown in Martin's comment). But I can't figure out a solution when the definition is based on \@namedef

The minimal-non-working-example

This is what I tried:

\documentclass[11pt,a4paper]{article}
\usepackage{tikz}

\makeatletter

\newcommand{\setcolorlist}[1]{
        \foreach \listitem [count=\i] in {#1}{
            \global\let\@tempa\@namedef{color@\i}{\listitem}
        }
        \@tempa
}

% Command in which colors are necessary
\newcommand{\drawcoloredarrows}[1]{
    \foreach \i  in {#1}{
        \edef\mycolor{\@nameuse{color@\i}}
        \draw[\mycolor,-stealth] (0,-\i)--(2,-\i); 
    }
}

\makeatother

\begin{document}
\setcolorlist{red,cyan,blue,green}

\begin{tikzpicture}
    \drawcoloredarrows{1,...,4}
\end{tikzpicture}
\end{document}

getting:

enter image description here

How it should work

This is how it should work:

\documentclass[11pt,a4paper]{article}
\usepackage{tikz}

\makeatletter
\@namedef{color@1}{red}
\@namedef{color@2}{cyan}   
\@namedef{color@3}{blue} 
\@namedef{color@4}{green}  

\newcommand{\setcolorlist}[1]{
        \foreach \listitem [count=\i] in {#1}{
            \global\let\@tempa\@namedef{color@\i}{\listitem}
        }
        \@tempa
}

% Command in which colors are necessary
\newcommand{\drawcoloredarrows}[1]{
    \foreach \i  in {#1}{
        \edef\mycolor{\@nameuse{color@\i}}
        \draw[\mycolor,-stealth] (0,-\i)--(2,-\i); 
    }
}

\makeatother

\begin{document}
%\setcolorlist{red,cyan,blue,green}

\begin{tikzpicture}
    \drawcoloredarrows{1,...,4}
\end{tikzpicture}
\end{document}

getting:

enter image description here

share|improve this question
add comment

2 Answers

up vote 3 down vote accepted

With this macro

\newcommand{\setcolorlist}[1]{
        \foreach \listitem [count=\i] in {#1}{
            \global\let\@tempa\@namedef{color@\i}{\listitem}
        }
        \@tempa
}

you're basically doing

\global\let\@tempa\@namedef

and indeed "color@1red" and so on is printed. Then \@tempa (which is now \@namedef) has to be executed, which probably can't.

With \setcolorlist{red,green,blue} you want to do

\@namedef{color@1}{red}
\@namedef{color@2}{green}
\@namedef{color@3}{blue}

so you want to say

\@namedef{color@\i}{<expansion of \listitem>}

but globally. Since \@namedef{x} expands to

\expandafter\def\csname x\endcsname

and you need to access the expansion of \listitem, the following will do

\newcommand{\setcolorlist}[1]{%
  \foreach \listitem [count=\i] in {#1}{%
     \global\@namedef{color@\i\expandafter}\expandafter{\listitem}
  }%
}

Alternatively, since you know that \listitem and \i expand to a string,

\newcommand{\setcolorlist}[1]{%
  \foreach \listitem [count=\i] in {#1}{%
     \begingroup\edef\x{\endgroup
       \global\noexpand\@namedef{color@\i}{\listitem}}\x
  }%
}

Notice that Ahmed method works too, because at each successive step \listitem is defined to expand to the current color name. However that method would fail if you need to do something more complicated that a simple macro equivalence.


Mandatory expl3 solution

\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\setcolorlist}{ m }
 {
  \claudio_setcolorlist:n { #1 }
 }
\int_new:N \l_claudio_cycle_int
\cs_new_protected:Npn \claudio_setcolorlist:n #1
 {
  \int_zero:N \l_claudio_cycle_int
  \clist_map_inline:nn { #1 }
   {
    \int_incr:N \l_claudio_cycle_int
    \cs_set:cpn { color@ \int_to_arabic:n { \l_claudio_cycle_int } } { ##1 }
   }
 }
\ExplSyntaxOff

You can choose whether doing the assignments globally or locally (use \cs_gset:cpn in the former case), but this is not necessary. So this method is superior to the \foreach one, as it doesn't force you to do global definitions unless you need to.

share|improve this answer
    
Great answer, thanks. This is a good starting point not only to understand expansions, but also for LaTeX3 because I'm planning to have a look soon at it. –  Claudio Fiandrino Oct 26 '12 at 15:43
add comment

Try

\documentclass[11pt,a4paper]{article}
\usepackage{tikz}

\makeatletter
\newcommand{\setcolorlist}[1]{%
   \foreach \listitem [count=\i] in {#1}{
      \global\expandafter\let\csname color@\i\endcsname\listitem
   }
}

% Command in which colors are necessary
\newcommand{\drawcoloredarrows}[1]{
    \foreach \i  in {#1}{
        \draw[\@nameuse{color@\i},-stealth] (0,-\i)--(2,-\i); 
    }
}

\makeatother

\begin{document}
\setcolorlist{red,cyan,blue,green}
\begin{tikzpicture}
\drawcoloredarrows{1,...,4}
\end{tikzpicture}
\end{document}

Here is my preferred approach:

\documentclass{article}
\usepackage{tikz}
\usepackage{keyreader}
\makeatletter
\krddefinekeys{claudiocolor}[claudio@col@]{%
  cmd/1/black;cmd/2/black;cmd/3/black;cmd/4/black;cmd/5/black;cmd/6/black;
}
\newcommand*\setcolorlist[1]{\krdsetkeys{claudiocolor}{#1}}
\newcommand*\usecolor[1]{\@nameuse{claudio@col@#1}}
% Command in which colors are necessary:
\newcommand*\drawcoloredarrows[1]{%
  \foreach \x in {#1}{%
    \draw[\usecolor\x,-stealth] (0,-\x)--(2,-\x);
  }%
}
\makeatother

\begin{document}
\setcolorlist{1=red,2=blue,3=cyan,4=green,5=magenta,6=purple}
\begin{tikzpicture}
\drawcoloredarrows{1,...,4}
\end{tikzpicture}
\end{document}
share|improve this answer
    
The \setcolorlist works perfectly, thanks. :) So, basically, the definition by means of \@namedef was not a good choice. I should really study the expansions... –  Claudio Fiandrino Oct 25 '12 at 16:56
    
You have a redundant \expandafter. :) –  egreg Oct 25 '12 at 17:22
    
@egreg: Thanks. Removed. –  Ahmed Musa Oct 26 '12 at 14:04
add comment

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.