Not repeating myself so much in TikZ diagrams

You can use for loops to repeat stuff in TikZ. This is described in chapter 56, Repeating Things: The Foreach Statement in the manual.

For example, you could draw the vertical lines and make the coordinate nodes with

\foreach \x/\y/\n in {C0/Cn/C, S0/Sn/S}
 {\draw (\x) -- (\y)
  \foreach [count=\name] \p in {0.10,0.19,0.32,0.45,0.58,0.67,0.8}
   {node[pos=\p] (\n\name) {}};
 };

This will go through the loop for each of the \x/\y/\n combinations. So the first time through it will draw the line from C0 to Cn, then go through the "inner" loop, where the coordinate nodes are placed along this line. The count=\name option allows you to access the index of the item in the list. Hence, \n\name will give you C1, C2 etc.


You also asked for a way to position arrow endpoints an absolute distance along the line. There are probably several ways of doing this, the following uses the calc library for coordinate calculations:

\foreach [count=\name] \y in {1,2,...,7} {
  \coordinate (C\name) at ($(C0) + (0,-\y)$);
  \coordinate (S\name) at ($(S0) + (0,-\y)$);
  };

1,2,...,7 is the same as 1,2,3,4,5,6,7. This places coordinates a distance \y below the C0 and S0 nodes. Of course, this method doesn't work well for non vertical (or non horizontal) lines.


You don't even need the calc library here. Since you can use \foreach inside of a \draw sequence:

\node (C0) at (0.2,0) {$C$};
\draw (C0)
    \foreach [count=\name] \y in {0.77, 0.693, 1.001, 1.001, 1.001, 0.693, 1.001, 1.54}
    {
        -- ++(0,-\y) coordinate (C\name) 
    };

The [count=\name] syntax I learned from Torbjørn T. (thanks!). The benefit is that you don't have to calculate the whole length, because you only give the difference between two coordinates. Now we can wrap this code easily into a macro:

\newcommand{\drawparties}[1]{
    \node (C0) at (0.2,0) {$C$} ;
    \draw (C0)
        \foreach [count=\name] \y in {#1}
        {
            -- ++(0,-\y) coordinate (C\name) 
        };
    \node (S0) at (4.8,0) {$S$};
    \draw (S0) 
        \foreach [count=\name] \y in {#1}
        {
            -- ++(0,-\y) coordinate (S\name) 
        };
}

Note: this macro does not depend on the numbers of the drawn nodes. We can also shorten your arrow code, if it is really such repetitive as in your example to:

\newcommand{\drawsend}[2]{\draw[->,>=angle 60] (C#1) -- node[above, font={\footnotesize}] {$C^\prime_\alpha[\alpha,#2]$} (S#1);}
\newcommand{\drawreceive}[2]{\draw[<-,>=angle 60] (S#1) -- node[above, font={\footnotesize}]{$S^\prime_\alpha[\alpha,#2]$} (C#1);}

Then the whole code cooks down to:

\begin{tikzpicture}
    \drawparties{0.77, 0.693, 1.001, 1.001, 1.001, 0.693, 1.001, 1.54}

    \drawsend{1}{99,l_r,,\cdots}
    \drawsend{2}{100,l_s,\text{\textsc{fin}},\cdots}
    \drawreceive{3}{60,l_t,,\cdots}
    \drawsend{4}{101,0,,}
    \drawreceive{5}{61,l_u,,\cdots}
    \drawreceive{6}{62,l_v,,\cdots}
    \drawsend{7}{102,0,,}
\end{tikzpicture}

I personally don't like to use macros (like the one above) in tikz because they feel like an alien body inside of a tikzpicture. But in this case you can really save some typing in particular if you are using it more than one time.


I think you can get away with a TikZ matrix as follows:

\documentclass{article}
\usepackage{amsmath,tikz}
\usetikzlibrary{arrows,matrix}
\begin{document}
\begin{tikzpicture}[>=angle 60,every left delimiter/.style={xshift=1.5ex},%
every right delimiter/.style={xshift=-1.5ex}]
\matrix[matrix of math nodes,nodes in empty cells,row sep={9mm,between origins},%
nodes={minimum width=4cm},left delimiter=|,right delimiter=|,%
label={north east:$S$},label={north west:$C$}] (listmat) at (0,4) 
{\\
C^\prime_\alpha[\alpha,99,l_r,,\cdots]\\
C^\prime_\alpha[\alpha,100,l_s,\text{\textsc{fin}},\cdots]\\
S^\prime_\alpha[\alpha,60,l_t,,\cdots] \\
C^\prime_\alpha[\alpha,101,0,,]\\
S^\prime_\alpha[\alpha,61,l_u,,\cdots]\\
S^\prime_\alpha[\alpha,62,l_v,,\cdots]\\
C^\prime_\alpha[\alpha,102,0,,]\\
\\
}; 
\def\alef{<-}
\def\arig{->}
\foreach \x/\ddir in {2/\arig,3/\arig,4/\alef,5/\arig,6/\alef,7/\alef,8/\arig}{
\draw[\ddir] (listmat-\x-1.south west) --  (listmat-\x-1.south east);
}
\end{tikzpicture}
\end{document}

Here is the result

code output

I am committing a few TeX crimes by defining things in a very bad location etc. Moreover, the numbers a bit hand-tuned. The lame variable names are to avoid conflicts. I didn't spend more time on it since I am not even sure if this is what you wanted. If you wish to use, please let me know which part needs tweaking or a remake.

Tags:

Tikz Pgf