4

I'm trying to use a foreach loop to draw a whole bunch of arrows in a tikzcd environment by using the foreach loop to specify coordinates but I can't get it to compile. Here's a minimal example of what I'm trying:

\documentclass{article}

\usepackage{tikz-cd}

\begin{document}

\begin{tikzcd}
  A & B & C \\
  \foreach \x in {2,3}{
    \arrow[from=1-1, to=1-\x]
  }
\end{tikzcd}

\end{document}

Which should appear as an arrow from A to B and another from A to C. Instead I'm recieving this error:

ERROR: Undefined control sequence.

--- TeX said ---

pgf@sh@ns@\tikzcdmatrixname -1-\x

l.12 \end{tikzcd}

I think I could get it to work in a plain tikz environment but I'd like to use tikzcd if possible. Thanks for any help.

4
  • 1
    on your way it is not possible in tikz-cd. compare your approach with standard tikz-cd syntax: A \ar[r]& B\ar[r] & C and you will see, that arrows there is modified (starting point is defined with cell where its command is placed and end in cell defined by option r. check the manual, if there is mentioned possibilities of what you like to have.
    – Zarko
    Commented Apr 25, 2019 at 7:47
  • If I replace the code in the tikzcd environment with just A & B \\ followed by \arrow[from=1-1, to=1-2] then it compiles correctly. The problem appears to be in putting the variable \x in as a coordinate.
    – aardvark
    Commented Apr 25, 2019 at 7:56
  • do you try to direct arrow from the first cell directly to the last? frankly said, i don't see any benefits with writing arrows on the your way. good luck in searching for solution which you like to obtain :-)
    – Zarko
    Commented Apr 25, 2019 at 8:02
  • Yes, I should have said an arrow from A to B and an arrow from A to C. What I'm trying to do in the end is draw a cube diagram with 4x4x4 nodes made of lots of smaller cubes. There would be 144 arrows so I'd quite like to use foreach so I don't have to write them all out. Thanks :)
    – aardvark
    Commented Apr 25, 2019 at 8:11

2 Answers 2

3

Try with a \draw in execute at end picture:

\documentclass{article}

\usepackage{tikz-cd}

\begin{document}

\begin{tikzcd}[
    every matrix/.append style={name=mymatrix},
    execute at end picture={
        \foreach \x in {2,3}{
            \draw[->] (mymatrix-1-1) -- (mymatrix-1-\x);
        }
    }
]
  A & B & C \\
\end{tikzcd}

And Zarko's example:

\begin{tikzcd}[
    every matrix/.append style={name=mymatrix},
    execute at end picture={
         \foreach \x [count=\xx] in {2,3}{ \draw[->] (mymatrix-1-\xx) -- (mymatrix-1-\x); 
         }
    }
]
  A & B & C \\
\end{tikzcd}
\end{document}

enter image description here

6
  • i'm glad to see, that i was wrong in my comment! to your example i would add the following example: ` \foreach \x [count=\xx] in {2,3}{ \draw[->] (mymatrix-1-\xx) -- (mymatrix-1-\x); } :-) +1 for answer
    – Zarko
    Commented Apr 25, 2019 at 8:39
  • thanks for your answer - this worked for me
    – aardvark
    Commented Apr 25, 2019 at 8:43
  • i store your answer in my barn of tikz-cd solutions. i very liked it!
    – Zarko
    Commented Apr 25, 2019 at 8:46
  • @Zarko What an honor! :) Thanks
    – CarLaTeX
    Commented Apr 25, 2019 at 9:15
  • When delete every matrix/.append style={name=mymatrix} in the second environment, it still works. It seems that the same option in the first environment works globally. Is it designed to work like this?
    – jiaopjie
    Commented Dec 4, 2021 at 14:52
2

This is a classical expansion problem.

The \arrow macro just takes everything between [ and ] and stores it as-is in a long list which gets processed much later. At that point \x isn't 2 or 3 anymore.

I provide three solutions:

  1. An \arrowx[<opt1>][<opt2>] macro that expands <opt1> before it processes it. The <opt2> will get forwarded as-is and not expanded. That will only be really necessary when you have to use fragile node content.

  2. The \arloop{<opt>}{<list>} macro uses a \foreach loop (i.e. the ... syntax is allowed) over <list> to construct \arrow[<opt>] statements where #1 in <opt> is replaced by the elements of your list.

  3. The end arrows key that executes its argument directly (after the nodes have been constructed, of course) when there's no expansion issue anymore.

(The PGFPlots package also provides various ungrouped and/or invoking loop constructs but these seem easy enough to implement just for TikZ-CD.)

Code

\documentclass{standalone}
\usepackage{tikz-cd}
\makeatletter
\tikzcdset{every diagram/.append code=\let\arrowx\tikzcd@arrowx\let\arloop\tikzcd@arloop}
\NewDocumentCommand{\tikzcd@arrowx}{O{}O{}}{%
  \edef\tikzcd@temp{#1}%
  \expandafter\arrow\expandafter[\expandafter{\tikzcd@temp,#2}]}
\NewDocumentCommand{\tikzcd@arloop}{mm}{%
  \pgfkeys{/utils/temp/.code=\arrow[{#1}],/utils/temp/.list={#2}}}
\NewDocumentCommand{\tikzcd@arrowlate}{O{}}{%
  \path[{/tikz/commutative diagrams/.cd,every arrow,#1}]
    (\tikzcd@ar@start\tikzcd@startanchor)to(\tikzcd@ar@target\tikzcd@endanchor);}
\tikzcdset{
  end arrows/.style={
    /tikz/commutative diagrams/every matrix/.append style={
      append after command=
        \pgfextra{\pgfutil@g@addto@macro\tikzcd@savedpaths{\let\arrow\tikzcd@arrowlate#1}}}}}
\makeatother
\begin{document}
\begin{tikzcd}
  A & B & C
  \foreach \x in {2, 3}{
    \arrowx[from=1-1, to=1-\x, bend right]
  }
\end{tikzcd}
\begin{tikzcd}
  A & B & C
  \arloop{from=1-1, to=1-#1, bend left}{2,3}
\end{tikzcd}
\begin{tikzcd}[
  end arrows={
    \foreach \x in {2, 3}{
      \arrow[from=1-1, to=1-\x, bend right]
    }
  }
]
  A & B & C
\end{tikzcd}
\end{document}

Output

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .