5

I hope somebody can help me with this. I did already search for it, but none of the solutions seem to work. I'm trying to plot a simple graph, but the bend edges do overlap my nodes. That is, of course, undesirable. What I have so far:

\documentclass[10pt]{article}

\usepackage{tikz}
\usetikzlibrary{arrows}
\usetikzlibrary{positioning}

\begin{document}

\begin{tikzpicture}[->,>=stealth',auto,node distance=2cm,
  thick,main node/.style={draw,font=\sffamily\Large\bfseries}]

  \node[main node, rectangle, align=center] (1) {Crawling \\ Application};
  \node[main node, circle, align=center] (2) [right =of 1] {Crawl \\ Manager};
  \node[main node, rectangle] (3) [right =of 2] {Downloader};
  \node[main node, rectangle] (4) [right =of 2, below =of 3] {Downloader};
  \node[main node, rectangle] (5) [right =of 2, above =of 3] {Downloader};
  \node[main node, rectangle, align=center] (6) [below =of 2] {DNS \\ resolver};

  \path[every node/.style={font=\sffamily\small}]
    (1) edge node [right] {URL requests} (2)
    (2) edge node [right] {} (3)
    (2) edge node [right] {} (4.west)
    (2) edge node [right] {} (5.west)
    (2) edge node [below] {} (6)
    (3.east) edge[bend right, out=180,in=270] node [left] {} (2.north)
    (4.east) edge[bend right, out=180,in=270] node [left] {} (2.north)
    (5.east) edge[bend right, out=180,in=270] node [left] {} (2.north)
    (3.east) edge[bend left, out=180,in=90] node [left] {} (1.south)
    (4.east) edge[bend left, out=180,in=90] node [left] {} (1.south)
    (5.east) edge[bend left, out=180,in=90] node [left] {} (1.south);
\end{tikzpicture}
\end{document}

And the resulting graph: enter image description here

I would like to have the curved arrows bend so that the ones going into the circle are above the highest "Downloader" rectangle and the ones going into the rectangle are below the "DNS resolver" rectangle. If possible, they should converge on their way, so that it is only one line. But that's optional. And, if some Tex-magic is necessary, I need to place a label on top of the upper arrows and one below the lower arrows later.

Thanks for the help already!

  • I think my answer to this question may help you figure it out: tex.stackexchange.com/a/223095/36686 – Bordaigorl Feb 14 '17 at 10:47
  • @Bordaigorl So there is no simple solution. I will have a look, hopefully it works. – Patrick Feb 14 '17 at 11:04
  • I believe that the question you could be solve looking at the site tex.stackexchange.com/questions/69319/…. – Sebastiano Feb 14 '17 at 11:31
  • I think playing with the in out and looseness parameters until you are happy should not be too difficult. Make sure you understand their meaning first on a simple example (as the one in the other answer). Automatic edge routing requires a completely different approach and would probably be an over-kill in this case – Bordaigorl Feb 14 '17 at 11:49
  • It will work, that's true. But I hoped for an automatic solution. Adjusting it manually costs time. An automatic solution would be more elegant. – Patrick Feb 14 '17 at 12:09
5

Not a completly automated solution, but one which shows some (hopefully) useful tricks.

The figure is drawn in three phases:

  1. The first phase draws the nodes and give them names. The code for this part is identical to your code, but I also define two extra auxiliar coordinates, one at the top of the uppermost "Downloader", and another below the "DNS Resolver" box.
  2. The edges unrelated to nodes 3, 4, and 5 are drawn separately, using to syntax, instead of edge node [right] {}, since most of your edges are not labeled and do not require those artificial empty nodes. The line (1) to (2) is labeled with a midway node.
  3. The edges related to nodes 3, 4 and 5 are drawn in a loop. For each "Downloader", three edges are drawn:
    1. One straight line from (2)
    2. One curved line to (2.north) passing above all "Downloaders"
    3. One curved line to (1.south) passing below "DNS Resolver"

These curved lines are the tricky ones. I used out, in and looseness to control the curvature, but also made use of the auxiliar coordinates top and bottom to have more control of the general shape. Each "top" curve passes through two horizontally aligned points, at coordinates (top) and (top-|bottom), plus a small offest with depends on the loop iteration, to avoid all lines overlapping in a single one. A similar strategy is used for the bottom curves.

This is the code:

\documentclass[tikz, border=5pt]{standalone}

\usepackage{tikz}
\usetikzlibrary{arrows}
\usetikzlibrary{positioning,calc}

\begin{document}

\begin{tikzpicture}[->,>=stealth',auto,node distance=2cm,
thick,main node/.style={draw,font=\sffamily\Large\bfseries}]

% Phase 1
\node[main node, rectangle, align=center] (1) {Crawling \\ Application};
\node[main node, circle, align=center] (2) [right =of 1] {Crawl \\ Manager};
\node[main node, rectangle] (4) [right =of 2] {Downloader};
\node[main node, rectangle] (3) [right =of 2, below =of 4] {Downloader};
\node[main node, rectangle] (5) [right =of 2, above =of 4] {Downloader};
\node[main node, rectangle, align=center] (6) [below =of 2] {DNS \\ resolver};
\coordinate[above=of 5.north east] (top);
\coordinate[below=of 6.south east] (bottom);

% Phase 2
\draw (1) edge node[above, midway, font=\sffamily\small] {URL requests} (2) ;
\draw (2) to (6);

% Phase 3
\foreach \n in {3,4,5} {
    \draw (2) to (\n.west);
    \draw (\n.east) to[out=10,in=0,looseness=1.8] ($(top)+(0,-\n/3)$) to ($(top-|bottom)+(0,-\n/3)$) to[out=180,in=90] (2.north);
    \draw (\n.east) to[out=-20,in=0,looseness=1.2] ($(bottom-|top)+(0,2-\n/3)$) to ($(bottom)+(0,2-\n/3)$)
    to[out=180,in=-90] (1.south);
}

\end{tikzpicture}
\end{document}

And this is the result: Result

Update. I've just noticed the optional requirement of the OP "If possible, they should converge on their way, so that it is only one line. But that's optional."

Indeed, the solution is simpler, because no calc is required to "move" the auxiliar coordinates for each iteration of the loop:

\documentclass[tikz, border=5pt]{standalone}

\usepackage{tikz}
\usetikzlibrary{arrows}
\usetikzlibrary{positioning,calc}

\begin{document}

\begin{tikzpicture}[->,>=stealth',auto,node distance=2cm,
  thick,main node/.style={draw,font=\sffamily\Large\bfseries}]

  \node[main node, rectangle, align=center] (1) {Crawling \\ Application};
  \node[main node, circle, align=center] (2) [right =of 1] {Crawl \\ Manager};
  \node[main node, rectangle] (4) [right =of 2] {Downloader};
  \node[main node, rectangle] (3) [right =of 2, below =of 4] {Downloader};
  \node[main node, rectangle] (5) [right =of 2, above =of 4] {Downloader};
  \node[main node, rectangle, align=center] (6) [below =of 2] {DNS \\ resolver};
  \coordinate[above=of 5.north east] (top);
  \coordinate[below=of 6.south east] (bottom);

  % Phase 2
  \draw (1) edge node[above, midway, font=\sffamily\small] {URL requests} (2) ;
  \draw (2) to (6);

  % Phase 3
  \foreach \n in {3,4,5} {
      \draw (2) to (\n.west);
      \draw (\n.east) to[out=10,in=0,looseness=1] (top) to (top-|bottom) to[out=180,in=90, looseness=0.7] (2.north);
      \draw (\n.east) to[out=-20,in=0,looseness=1] (bottom-|top) to (bottom) to[out=180,in=-90, looseness=1] (1.south);
  }
\end{tikzpicture}
\end{document}

Result2

| improve this answer | |
5

An alternative, without bending lines ... and more concise code for nodes:

\documentclass[tikz, border=5pt]{standalone}
\usetikzlibrary{arrows, positioning, quotes}

\begin{document}
    \begin{tikzpicture}[auto, thick,
    node distance = 1cm and 2.4 cm,
 main node/.style = {draw, font=\sffamily\Large\bfseries, align=center},
 every quotes label/.style = {font=\sffamily\footnotesize}
                        ]
\node[main node]                        (1) {Crawling \\ Application};
\node[main node, circle, right=of 1]    (2) {Crawl \\ Manager};
\node[main node, right=of 2]            (3) {Downloader};
\node[main node, below=of 3]            (4) {Downloader};
\node[main node, above=of 3]            (5) {Downloader};
\node[main node, below=of 2]            (6) {DNS \\ resolver};
  \coordinate[above=of 5.north] (top);
  \coordinate[below=of 6.south] (bottom);
%
\draw[-stealth']    
    (1) edge ["URL requests"] (2) 
    (2) edge (3)    
    (2) edge (4.west)
    (2) edge (5.west)
    (2) edge (6);
% 
\draw[-stealth', rounded corners=5mm] 
    ([yshift= 1mm] 3.east) -- ++ (0.5,0) |-  (top)    -| (2);
\draw[-stealth', rounded corners=5mm]
    ([yshift=-1mm] 3.east) -- ++ (1.0,0) |-  (bottom) -| (1);
\draw[rounded corners=5mm]
        ([yshift= 1mm] 4.east) -- ++ (0.5,0) |-  (top)
        ([yshift= 1mm] 5.east) -- ++ (0.5,0) |-  (top)
        ([yshift=-1mm] 4.east) -- ++ (1.0,0) |-  (bottom)
        ([yshift=-1mm] 5.east) -- ++ (1.0,0) |-  (bottom);
\end{tikzpicture}
\end{document}

enter image description here

| improve this answer | |

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.