18
\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{arrows}

\begin{document}
\begin{frame}
  \begin{figure}[h]
    \centering
    \begin{tikzpicture}[
      % type of arrow head
      >=stealth',
      % keep arrow head from touching the surface
      shorten >= 1pt,
      % automatic node positioning
      auto,
      % 
      node distance=1.2cm,
      % line thickness
      semithick,
      graybox/.style = {draw=gray!20, fill=gray!20, rounded corners},
      line/.style = {draw=black, thick},
      team/.style = {circle, draw=blue!50, fill=blue!20, minimum size=8mm}
    ]

    \coordinate (O) at (0cm, 0cm);

    % this node is named 'C1' and located at (O). Its style is 'team'
    \node [team] (C1) at (O) {\small 1};
    \node [team] (C2) [below of=C1] {\small 2};
    \node [team] (C3) [below of=C2] {\small 3};
    \node [team] (C4) [below of=C3] {\small 4};
    \node [team] (C5) [below of=C4] {\small 5};

    \path [line] (C5) --++ (1cm, 0cm) |- (C4);

    \end{tikzpicture}
  \end{figure}
\end{frame}
\end{document}

This is a LaTeX code that I wrote to generate a simple diagram.

enter image description here

But what I really want is something like this.

1 --------------+
                |
                |
2 ----------+   |
            |   |
            |   |
3 ------+   +---+
        |   |
        +---+
4 --+   |
    |   |
    +---+
    |
5 --+

I can connect 4 and 5 using |- command, but I don't know how to label in the middle of this vertical line and then connect it to 3. What is the best way to draw the above ASCII art in LaTeX?

  • I think this is a perfect use case for the udlr library of our @Qrrbrbirlbel that can be found in tex.stackexchange.com/questions/102385/… But I didn't use it and he warns about the incompatibility possibilities. In the meantime you can use the calc computation. – percusse Apr 12 '15 at 11:05
  • @percusse Indeed, the code in the answer you linked to is quite outdated (most likely my first version of the concept of udlr connections). I even found a bug where the connection between node and coordinate (and vice versa) fails. – Qrrbrbirlbel Apr 12 '15 at 16:45
  • Be careful with (node) ++(1cm,0cm) as it calculates the difference to the .center of node (which might just be inside the node itself), it also makes the first connection closer to the nodes as the other connections are to the previous connection. – Qrrbrbirlbel Apr 12 '15 at 19:18
  • Related: Node on a jointed TikZ path – Qrrbrbirlbel Apr 12 '15 at 19:18
18

The starting points on the line can be calculated. The following example takes the middle of the vertical line segment:

\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{arrows}
\usetikzlibrary{calc}

\begin{document}
\begin{frame}
  \begin{figure}[h]
    \centering
    \begin{tikzpicture}[
      % type of arrow head
      >=stealth',
      % keep arrow head from touching the surface
      shorten >= 1pt,
      % automatic node positioning
      auto,
      % 
      node distance=1.2cm,
      % line thickness
      semithick,
      graybox/.style = {draw=gray!20, fill=gray!20, rounded corners},
      line/.style = {draw=black, thick},
      team/.style = {circle, draw=blue!50, fill=blue!20, minimum size=8mm}
    ]

    \coordinate (O) at (0cm, 0cm);

    % this node is named 'C1' and located at (O). Its style is 'team'
    \node [team] (C1) at (O) {\small 1};
    \node [team] (C2) [below of=C1] {\small 2};
    \node [team] (C3) [below of=C2] {\small 3};
    \node [team] (C4) [below of=C3] {\small 4};
    \node [team] (C5) [below of=C4] {\small 5};

    \path [line] (C5) --++ (1cm, 0cm) coordinate (C45r) |- (C4);
    \path [line] ($(C5)!.5!(C4)$) coordinate (C45m)
                 (C45r |- C45m) --++ (1cm, 0cm) coordinate (C34r) |- (C3);
    \path [line] ($(C45m)!.5!(C3)$) coordinate (C34m)
                 (C34r |- C34m) --++ (1cm, 0cm) coordinate (C23r) |- (C2);
    \path [line] ($(C34m)!.5!(C2)$) coordinate (C23m)
                 (C23r |- C23m) --++ (1cm, 0cm) |- (C1);

    \end{tikzpicture}
  \end{figure}
\end{frame}
\end{document}

Result

  • Exactly what I wanted. Thank you very much! – user19906 Apr 12 '15 at 13:01
17

Here is a solution using coordinate and the pos option:

Another interesting case are the horizontal/vertical line-to operations |- and -|. For them, the position (or time) 0.5 is exactly the corner point.

(from pgfmanual, p. 236, section 17.8 Placing Nodes on a Line or Curve Explicitly)

After |-, with position 0.25, you get the middle of the vertical line.

enter image description here

\documentclass[tikz,margin=2mm]{standalone}
\usetikzlibrary{arrows}
\begin{document}
\begin{tikzpicture}[
  % type of arrow head
  >=stealth',
  % keep arrow head from touching the surface
  shorten >= 1pt,
  % automatic node positioning
  auto,
  % 
  node distance=1.2cm,
  % line thickness
  semithick,
  graybox/.style = {draw=gray!20, fill=gray!20, rounded corners},
  line/.style = {draw=black, thick},
  team/.style = {circle, draw=blue!50, fill=blue!20, minimum size=8mm}
  ]

  \coordinate (O) at (0cm, 0cm);
  % this node is named 'C1' and located at (O). Its style is 'team'
  \node [team] (C1) at (O) {\small 1};
  \node [team] (C2) [below of=C1] {\small 2};
  \node [team] (C3) [below of=C2] {\small 3};
  \node [team] (C4) [below of=C3] {\small 4};
  \node [team] (C5) [below of=C4] {\small 5};
  \path [line]    (C5) --++ (1cm, 0cm) |- coordinate[pos=.25] (r-4-5) (C4);
  \path [line] (r-4-5) --++ (1cm, 0cm) |- coordinate[pos=.25] (r-3-4) (C3);
  \path [line] (r-3-4) --++ (1cm, 0cm) |- coordinate[pos=.25] (r-2-3) (C2);
  \path [line] (r-2-3) --++ (1cm, 0cm) |- (C1);

\end{tikzpicture}
\end{document}
  • Elegant solution with pos=.25: +1 – Heiko Oberdiek Apr 12 '15 at 17:15
13

A few notes before hand:

  1. The arrows (and the arrows.spaced) library is deprecated since version 3.0 of TikZ/PGF. It still works, but the new arrows.meta library offers so much more options and reliability.
  2. The ? of=? syntax is deprecated (and really shouldn't be used anymore), see also Difference between "right of=" and "right=of" in PGF/TikZ. Use the positioning library and the below=? of ? syntax. The behavior of the old keys can be generated with the on grid options.
  3. I have used the chains library (which relieves us from using repeatable using \node and below=of. Some may say that even chains is "outdated" and the new graphs library is much more powerful (some would be correct). I added an example for the graphs library. Adding the edge paths inside the \graph options and/or as part of the graphs library is left to the reader.

Indeed, it seems my udlr family seems to help here. You will need the files

in your texmf tree or somewhere else where LaTeX can find them (in the same folder as your main .tex file for instance).

Amongst others it allows you to use the r-rl path operator which means to draw an orthogonal connection between to coordinates in which you start from the first and go to the right then up- or downwards and then left to the target coordinate (or node). You can write r-rl[distance=?] to change the distance between nodes/coordinates and the vertical part of the path (default: 0.5cm). The option from center adds the distance from the center of nodes (instead of their borders).

In your example I add an additional (auxiliary) name for the last node and add with the coordinate (@) a coordinate on the connection which allows me to use the same \path specification repeatedly. This @ coordinate (with an default pos=.5) is placed at middle of the vertical part of the r-rl connection.

All these options and how they effect the placement of nodes/coordinates along the path are explained in my answer to Vertical and horizontal lines in pgf-tikz.


If you still want to use |-, I'd advise you to use a to path as defined in:

rl/.style={
  near start,
  to path={(\tikztostart) -- ++(#1,0) |- (\tikztotarget) \tikztonodes}},
rl/.default=.5

and then you can easily do

\foreach \i in {4,...,1}
  \path (@.east) edge[line, rl] coordinate (@) (ch-\i);

Note that you have to .east otherwise the first connection is much closer to the 4 and 5 nodes as the distance in ++(X, Y) is calculates from the center of nodes. (A coordinate is only a point so the .east anchor is just the same as the coordinate without an anchor.)

The rl style also sets near start (which is a short-cut for pos=.25) so that it automatically uses a point halfway on the vertical part.

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{paths.ortho, chains, graphs}
\begin{document}
\begin{tikzpicture}[
  shorten >= 1pt, node distance=.4cm, semithick,
  line/.style = {draw=black, thick},
  team/.style = {circle, draw=blue!50, fill=blue!20, minimum size=8mm},
]
\begin{scope}[start chain=ch going below]
\foreach \i in {1,...,5} \node [on chain, team] {\small \i};
\end{scope}
\path (ch-end) [late options={alias=@}];
\foreach \i in {4,...,1}
  \path[line] (@) r-rl coordinate (@) (ch-\i);
\end{tikzpicture}
\begin{tikzpicture}[
  shorten >= 1pt, semithick,
  line/.style = {draw=black, thick},
  team/.style = {circle, draw=blue!50, fill=blue!20, minimum size=8mm}
]
\graph[name=C, branch down sep=.4cm, typeset=\small\tikzgraphnodetext, nodes=team]
  {\foreach \i in {1,...,5}{\i}};
\path (C 5) [late options={alias=@}];
\foreach \i in {4,...,1}
  \path[line] (@) r-rl coordinate (@) (C \i);
\end{tikzpicture}
\end{document}

Output

enter image description here

  • Very interesting solution. How someone, who don't know for given links for tikzlibrarypaths.ortho.code.tex and tikzlibrarypaths.ortho.tex, find them? Can I expected that they will be mentioned in next (cvs) version of TikZ manual? – Zarko Apr 12 '15 at 21:43
  • @Zarko Check my user-page. There will always be a link to the library files and the answers which spawned the idea for udlr as well as -|-/|-| (where the links are posted a second/third time). Tantau hasn't added these path operators into the recent version of TikZ (and maybe he hasn't seen it before or wasn't convinced), I don't believe they will be added in the future unless people ask him to do so. Nearly all functionality could be replicated with to path except—to my knowledge—the timer function (which translates the pos value in a coordinate). – Qrrbrbirlbel Apr 12 '15 at 21:57
6

Here is a short hacky solution using foreach:

\documentclass[tikz,border=7mm]{standalone}
\begin{document}
  \begin{tikzpicture}[team/.style={circle, draw=blue!50, fill=blue!20, minimum size=8mm}]
    \foreach[count=\i, remember=\k as \j (initially 0), evaluate={\k=.5*(\i+\j)}] \l in {4,...,1}
      \draw (\i-1,\j) -- ++(1,0) |- (0,\i) node[team]{\l};
    \node[team] {5}; % the final touch
  \end{tikzpicture}
\end{document}

enter image description here

6

For whom it may interest, here is a MetaPost solution, with the help of the boxes package.

\documentclass[border=2mm]{standalone}
\usepackage{luamplib}
  \mplibtextextlabel{enable}
\begin{document}
  \begin{mplibcode}
    input boxes; input mpcolornames;
    beginfig(1); 
      % circular boxes: definitions
      boxjoin(a.s - b.n = (0, .5cm)); circmargin := 3mm;
      for i = 1 upto 5:
        circleit.c[i]("\sffamily" & decimal i);
      endfor
      % circular boxes: drawings
      for i = 1 upto 5:
        fill bpath c[i] withcolor .25[white,blue];
        draw bpath c[i] withcolor blue;
        drawunboxed(c[i]);
      endfor
      % connexions defined and drawn iteratively
      h := .75cm; o := h;
      pair A, B, C, D; A = c4.e ; B = A + (h, 0); C = D + (h, 0); D = c5.e;
      draw A + (pt, 0) -- B -- C -- D;
      for i = 3 downto 1:
        h := h + o;
        D := .5[B, C]; A := c[i].e; B := A + (h, 0); C := D + (o, 0);
        draw A + (pt, 0) -- B -- C -- D;
      endfor 
    endfig; 
  \end{mplibcode}
\end{document}

To be processed with LuaLaTeX. Output:

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.