6

I am trying to reproduce the diagram below:

enter image description here

I'm wondering what I should use to generate this. I can make the matrix, that's simple, but getting the arrows right is what's difficult... It would be interesting to use this example, where the S_{ij}'s are circled nodes, and then some nodes just aren't connected, and the ellipses and the S_i:'s are nodes, but they wouldn't be circled. I'm looking here, and I think this would work too, but I don't yet know how to interpret the (m-i-j) symbolism, or how to connect arrows to nodes.


So far, I've got the following:

enter image description here

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows}
\begin{document}
\begin{tikzpicture}[->,>=stealth',shorten >=1pt,auto,node distance=3cm,
  thick,main node/.style={circle,fill=blue!20,draw,font=\sffamily\Large\bfseries}]

\node[main node] (1) {$S_{11}$};
\node[main node] (2) [right of=1] {$S_{12}$};
\node[main node] (3) [below of=1] {$S_{21}$};
\node[main node] (4) [below of=3] {$S_{31}$};
\node[main node] (5) [below of=2] {$S_{22}$};
\node[main node] (6) [right of=2] {$S_{13}$};
\node[main node] (7) [right of=6] {$S_{14}$};
\node[main node] (8) [below of=6] {$S_{23}$};
\node[main node] (9) [below of=5] {$S_{32}$};
\node[main node] (10) [below of=4] {$S_{41}$};

\node[main node] (11) [right of=10] {$S_{42}$};
\node[main node] (12) [right of=11] {$S_{43}$};
\node[main node] (13) [right of=12] {$S_{44}$};
\node[main node] (14) [right of=9] {$S_{33}$};
\node[main node] (15) [right of=14] {$S_{34}$};
\node[main node] (16) [right of=8] {$S_{24}$};

  \path[every node/.style={font=\sffamily\small}]
(1) edge node [right] {} (2)
(2) edge node [right] {} (3)
(3) edge node [right] {} (4)
(4) edge node [right] {} (5)
(5) edge node [right] {} (6)
(6) edge node [right] {} (7)
(7) edge node [right] {} (8)
(8) edge node [right] {} (9)
(9) edge node [right] {} (10);

\end{tikzpicture}
\end{document}
  • Maybe a commutative diagram would be better... – Trancot Aug 21 '13 at 22:47
  • How do you get rid of the circles? – Trancot Aug 21 '13 at 23:44
  • To get rid of the circles, remove circle,fill=blue!20,draw. – jub0bs Aug 21 '13 at 23:48
  • 1
    What is the question now? You can certainly make this diagram in another way. A \matrix or even tikz-cd come to mind. You could also simplify the connecting of the nodes or creating the matrix. – Qrrbrbirlbel Aug 22 '13 at 1:04
  • Since you have some responses below that seem to answer your question, please consider marking one of them as ‘Accepted’ by clicking on the tickmark below their vote count (see How do you accept an answer?). This shows which answer helped you most, and it assigns reputation points to the author of the answer (and to you!). It's part of this site's idea to identify good questions and answers through upvotes and acceptance of answers. – jub0bs Aug 26 '13 at 7:53
7

As Qrrbrbirlbel commented, you can use the \matrix command. The matrix of math nodes option from the matrix library will save you some typing by automatically turning on math mode in each cell. When you name a matrix (m), you can use the syntax (m-i-j) to refer to the cell in row i and column j of that matrix. To connect nodes, simply draw the edges after the matrix is set up.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}

\begin{document}

\begin{tikzpicture}
\matrix(m)[matrix of math nodes,column sep=1cm,row sep=1cm]{
    s_{11} & s_{12} & s_{13} & s_{14} & \cdots \\
    s_{21} & s_{22} & s_{23} & s_{24} & \cdots \\
    s_{31} & s_{32} & s_{33} & s_{34} & \cdots \\
    s_{41} & s_{42} & s_{43} & \cdots \\
};

\draw[->]
         (m-1-1)edge(m-1-2)
         (m-1-2)edge(m-2-1)
         (m-2-1)edge(m-3-1)
         (m-3-1)edge(m-2-2)
         (m-2-2)edge(m-1-3)
         (m-1-3)edge(m-1-4)
         (m-1-4)edge(m-2-3)
         (m-2-3)edge(m-3-2)
         (m-3-2)edge(m-4-1);
\end{tikzpicture}

\end{document}

enter image description here

  • Is there any option in the "matrix" command that allows to draw circles around the nodes? – boumol Aug 26 '13 at 8:28
  • 1
    @boumol: try nodes={circle,draw}; nodes sets the style for every node in the matrix, circle specifies the shape of the nodes, and draw draws the border of the nodes. You may also add keys like inner sep=<num> or minimum size=<num> to make node sizes uniform – Herr K. Aug 26 '13 at 10:46
  • @KevinC This one is the slickest. The rainbow guy's is good too. :-) – Trancot Aug 26 '13 at 23:27
6

Here is a solution that draws the edges automatically; no need to specify them one by one!

You can make the graph as big as you wish: simply specify the number of nodes you want by changing the value of positive integer \N.

Note: Failure to load the babel package with the english option will generate errors. See tikz-uml sequence diagram "Extra \or" error for more details.

Edit: See also Qrrbrbirlbel's "chains" solution, which is similar to mine in spirit.


enter image description here


enter image description here


\documentclass{article}
\usepackage[english]{babel}
\usepackage{etoolbox}
\usepackage{pgfplots}
\usetikzlibrary{arrows}
\begin{document}
\begin{tikzpicture}%
[
    ->,
    >=stealth',
    scale=2,
    auto,
  thick,
  main node/.style=%
  {
%   circle,
%   fill=blue!20,
%   draw,
    font=\sffamily\Large\bfseries,
  }
]
\pgfmathtruncatemacro\N{10}
\pgfmathtruncatemacro\i{1}
\pgfmathtruncatemacro\j{1}

\node[main node] at (\j,-\i) (n1) {$S_{\i\j}$};

\pgfplotsforeachungrouped \current in {1,2,...,\N-1}%
{
    \pgfmathtruncatemacro\next{\current+1}
    \ifnum\i=1% (first row)
        \ifnumodd{\j}%
        {   % Go East
            \pgfmathtruncatemacro\j{\j+1}
        }{% Go South West
            \pgfmathtruncatemacro\i{\i+1}
            \pgfmathtruncatemacro\j{\j-1}
        }
    \else% 
        \ifnum\j=1% (first column)
            \ifnumodd{\i}%
            { % Go North East
                \pgfmathtruncatemacro\i{\i-1}
                \pgfmathtruncatemacro\j{\j+1}
            }{% Go South
                \pgfmathtruncatemacro\i{\i+1}
            }
        \else
            \pgfmathtruncatemacro{\ijsum}{\i+\j}
            \ifnumodd{\ijsum}%
            { % Go South West
                \pgfmathtruncatemacro\i{\i+1}
                \pgfmathtruncatemacro\j{\j-1}
            }{% Go North East
                \pgfmathtruncatemacro\i{\i-1}
                \pgfmathtruncatemacro\j{\j+1}
            }
        \fi
    \fi
    \node[main node] at (\j,-\i) (n\next) {$S_{\i\j}$};
    \draw (n\current) -- (n\next);
}
\end{tikzpicture}
\end{document}
  • @Qrrbrbirlbel Thanks for your edit, but it may lead future visitors to believe I'm competent with the chains library, which is not true at all. Why not put that in your post rather than mine? – jub0bs Aug 22 '13 at 3:34
  • Alright, the solution I added is very similar to your solutions which seemed to be a better fit. But after all, the edit button is there and it is also wiki and such … – Qrrbrbirlbel Aug 22 '13 at 4:27
  • @Qrrbrbirlbel I just don't want to mislead future visitors as to what I'm familiar with. I appreciate the intention, but I think that alternative of yours rightfully belongs in your answer. We can always refer to each other's solutions in the text. – jub0bs Aug 24 '13 at 8:22
5

Matrix

It seems that a TikZ \matrix is the easiest approach here.

Combined with the execute at empty cell which fills the matrix automatically and the continous edges to style, you can create this diagram very fast.

Though, the arrows follow a pattern which can be automated, too:
This is done with the keys matrix connector urr (up-right, right) and matrix connector ldd (left-down, down) which initial a search algorithm that relies on named nodes in the matrix.

Code

\documentclass[tikz,convert=false]{standalone}
\usetikzlibrary{matrix}
\makeatletter
\tikzset{
  @continous edges to/.style={insert path={edge (#1) (#1)}},
  continous edges to/.style={@continous edges to/.list={#1}},
  matrix connector urr/.code args={#1-#2-#3}{%
    \pgfutil@ifundefined{pgf@sh@ns@#1-\the\numexpr#2-1\relax-\the\numexpr#3+1\relax}{%
      \pgfutil@ifundefined{pgf@sh@ns@#1-#2-\the\numexpr#3+1\relax}{}{
        \tikzset{insert path={(#1-#2-#3) edge (#1-#2-\the\numexpr#3+1\relax)},
                 matrix connector ldd/.expanded={#1-#2-\the\numexpr#3+1\relax}}%
      }%
    }{%
      \tikzset{insert path={(#1-#2-#3) edge (#1-\the\numexpr#2-1\relax-\the\numexpr#3+1\relax)},
               matrix connector urr/.expanded={#1-\the\numexpr#2-1\relax-\the\numexpr#3+1\relax}}%
    }
  },
  matrix connector ldd/.code args={#1-#2-#3}{%
    \pgfutil@ifundefined{pgf@sh@ns@#1-\the\numexpr#2+1\relax-\the\numexpr#3-1\relax}{%
      \pgfutil@ifundefined{pgf@sh@ns@#1-\the\numexpr#2+1\relax-#3}{}{%
        \tikzset{insert path={(#1-#2-#3) edge (#1-\the\numexpr#2+1\relax-#3)},
                 matrix connector urr/.expanded={#1-\the\numexpr#2+1\relax-#3}}%
      }%
    }{%
      \tikzset{insert path={(#1-#2-#3) edge (#1-\the\numexpr#2+1\relax-\the\numexpr#3-1\relax)},
               matrix connector ldd/.expanded={#1-\the\numexpr#2+1\relax-\the\numexpr#3-1\relax}}%
    }
  },
}
\makeatother
\begin{document}
\begin{tikzpicture}
\matrix (m) [
  matrix of nodes,
  nodes={
    shape=circle,
    inner sep=+.1667em,% half the default value
  },
  execute at empty cell={\node {$S_{\the\pgfmatrixcurrentrow\the\pgfmatrixcurrentcolumn}$};},
  row sep=2em,
  column sep=2em
] {
  & & & \\
  & & & \\
  & & & \\
  & & & \\
};
\path[->, ultra thick, matrix connector urr={m-1-1}];
\path[->,white, shorten >=2\pgflinewidth] (m-1-1) [continous edges to={m-1-2, m-2-1, m-3-1, m-2-2, m-1-3, m-1-4, m-2-3, m-3-2, m-4-1}];
\end{tikzpicture}
\end{document}

Output

enter image description here

Chains

An alternative approach, similar to Jubobs' answer, can be implemented with the chains library where one can use the placement options of the positioning library (i.e. on grid, node distance) for greater control. It is only used to place the nodes that are connected.

Code

\documentclass[tikz,convert=false]{standalone}
\usetikzlibrary{chains}
\newcommand*{\subscript}[3][]{%
    \ifodd#2
      \the\numexpr#2+1-#3\relax#1#3%
    \else
      #3#1\the\numexpr#2+1-#3\relax
    \fi}
\tikzset{
  zigzag/.code 2 args={%
    \ifnum#1>1
      \ifodd#1
        \ifnum#2=1
          \def\position{below}%
        \else
          \def\position{above right}%
        \fi
      \else
        \ifnum#2=1
          \def\position{right}%
        \else
          \def\position{below left}%
        \fi
      \fi
      \tikzset{\position=of \tikzchainprevious}
    \fi
  },
  zigzag*/.code={%
    \edef\llevel{\number\tikzchaincount}%
    \pgfmathloop
      \edef\testllevel{\the\numexpr\llevel-\pgfmathcounter\relax}%
      \ifnum1>\testllevel\relax
        \let\level\pgfmathcounter
      \else
        \let\llevel\testllevel
    \repeatpgfmathloop
    \tikzset{zigzag=\level\llevel}%
  }
}
%
\tikzset{
  every label/.append style={inner sep=+0pt, outer sep=+0pt, font=\tiny},
  label position=above left,
  every join/.append style={-latex},
}
\begin{document}
\begin{tikzpicture}[
  start chain=ch going {zigzag=\level\llevel},
  node distance=.75cm and 1cm,
  every on chain/.append style={
    join, label={(\number\tikzchaincount)}}]
\foreach \level in {1,...,4}
  \foreach \llevel in {1,...,\level}
    \node[on chain=ch] {$S_{\subscript[,]\level\llevel}$};
\end{tikzpicture}
\begin{tikzpicture}[
  on grid, node distance=1cm and 1.5cm, start chain=ch placed zigzag*,
  every on chain/.append style={
    circle, inner sep=+.1667em, text depth=+0pt, text height=+1.5ex,
    join, label/.expanded={(\noexpand\subscript[/]{\level}{\llevel})}}]
\foreach \cnt in {a,...,f} \node[on chain=ch] {\cnt};
\foreach \cnt in {G,...,M} \node[on chain=ch] {\cnt};
\end{tikzpicture}
\end{document}

Output

enter image description here

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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