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.

I want to draw several tikz picture like these ones, but with different numbers of nodes in each row and arrows between the top and bottom row between different nodes.

e.g parallel chains and another parallel chain etc.

I want to create a macro, that I can reuse for every drawing. For example that is parametrized with 3 lists, 2 lists listing the nodes in the top and bottom rows e.g. [h_0,h_1,h_2], [h'_0,h'_1] and one that is a list of pairs [(h_0,h'_0), (h_2,h'_1)] - so the macro will draw the two chains and then draw an arrow between the node in the top row and the node in the bottom row for each of the given pairs.

I am quite a Latex beginner and I am unsure really where to start or what is a reasonable way in Latex to approach this sort of parametrization and iteration.

This is the markup I used to draw the above diagram:

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{arrows,chains,scopes}

\begin{document}
\begin{tikzpicture} 
{[node distance=0.4cm,
  start chain=going right,
  every join/.style=->]
 \node [on chain] (start) {$h_0$};
 \node [on chain,join] {$h_1$};
 \node [on chain,join] {$h_2$};
 \node [on chain,join] (C1) {$h_3$}; 

 \node [on chain, below=1cm of start] (start) {$h_0'$};
 \node [on chain,join] {$h_1'$};
 \node [on chain,join] {$h_2'$};
 \node [on chain,join] {$h_3'$}; 
 \node [on chain,join] (C2) {$h_4'$}; 

 \draw[thick,<->] (C1.south east)--(C2.north west);
}
\end{tikzpicture}

\end{document}
share|improve this question

1 Answer 1

up vote 7 down vote accepted

With three \foreach loops, this can be done fairly simple.

As the scopes library does not play nice with chains created inside a \foreach loop (→ using foreach to draw a chain with a branch), I used the full \begin{scope} syntax.

The to-be-connected nodes list use a different syntax than requested in your question, namely

from1/to1, from2/to2, from3/to3, …

This is done mainly because it is easier to code a loop around it. It wouldn’t be too hard to use a nested list syntax, though.

All nodes have three names:

  • twoStoryChain<node content>, e.g. twoStoryChainh_1;
  • twoStoryChain<row number>-<node content>, e.g. twoStoryChainI-h_1; or
  • twoStoryChain<row number>-<index>, e.g. twoStoryChainI-0.

You can access nodes by its content if they are unique, by their row number and their content if they are unique row-wise, or by their row number and their row index if all fails (will always be unique). Take a look at the last TikZ picture. All solutions are presented.

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{arrows,chains,scopes}
\newcommand*{\twoStoryChain}[3]{% #1 = top row,
                                % #2 = second row,
                                % #3 = connected nodes
    \edef\qrrRowI{#1}
    \edef\qrrRowII{#2}
    \edef\qrrConnectedNodes{#3}
    \begin{scope}[
        node distance=0.4cm,
        start chain=going right,
        every join/.style=->
    ]
        \foreach \element[count=\iElement from 0] in \qrrRowI {
            \ifnum\iElement=0
                \node[on chain, name={twoStoryChainI-\element}, alias={twoStoryChainI-\iElement}, alias={twoStoryChain\element}] {$\element$};
            \else
                \node[on chain, name={twoStoryChainI-\element}, alias={twoStoryChainI-\iElement}, alias={twoStoryChain\element}, join] {$\element$};
            \fi
        }
    %
        \foreach \element[count=\iElement from 0] in \qrrRowII {
            \ifnum\iElement=0
                \node[on chain, name={twoStoryChainII-\element}, alias={twoStoryChainII-\iElement}, alias={twoStoryChain\element}, below=1cm of twoStoryChainI-0] {$\element$};
            \else
                \node[on chain, name={twoStoryChainII-\element}, alias={twoStoryChainII-\iElement}, alias={twoStoryChain\element}, join] {$\element$};
            \fi
        }
    \end{scope}
    \foreach \fromNode/\toNode in \qrrConnectedNodes {
        \draw[thick, <->] (twoStoryChain\fromNode) -- (twoStoryChain\toNode);
    }
}
\begin{document}
\begin{tikzpicture}
\twoStoryChain{h_0,h_1,h_2,h_3}{h_0', h_1',h_2',h_3',h_4'}{h_3/h_4'}
\end{tikzpicture}
\begin{tikzpicture}
\twoStoryChain{h_0,h_1,h_2}{h_0', h_1',h_2',h_3',h_4'}{h_1/h_2',h_2/h_4'}
\end{tikzpicture}
\begin{tikzpicture}
\twoStoryChain{h_0,h_0,h_1,h_3}{h_0,h_0,h_1,h_2,h_4}{%
    h_2/h_3,%      names like content
    I-h_1/II-h_1,% names like content but with number of chain
    I-0/II-1,%  or names with an index
    I-1/h_4%    or mixed
    }
\end{tikzpicture}
\end{document}

Output

enter image description here enter image description here enter image description here

share|improve this answer
    
Wow, that is much cleaner than I had imagined. Are the "\edef" names given to each parameter at the top necessary, I notice that each is used only once? –  flamingpenguin Feb 23 '13 at 11:31
1  
@flamingpenguin That depends highly on your kind of input. The \edefs are basically there so that you can use \twoStoryChain with a prepared list stored in another macro (i.e. \twoStoryChain{\myFirstRow}{\mySecondRow}{I-0/II-3}). If you do not want/need this, you can replace the \qrr… macros in the for-each loops with {#1}, {#2} and {#3} accordingly. Note that using non-expandable macros for the elements (for example \mathrm) will break this algorithm twice: Firstly in the \edef part (which can be avoided, see above), then when it is used as part of the node name. –  Qrrbrbirlbel Feb 23 '13 at 15:02

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.