1

I would like to draw two parallel arrows between two nodes in TikZ. The difficulty is that the nodes can be of any size and can be arranged in any order.

Related:

The question Parallel arrows between nodes of varying size deals with a similar problem, but the positions of the nodes are not arbitrary.

I would also like to be able to customize the arrows individually (e.g., different colors or show them one after the other in the presentation). Therefore, the answers to the question Connect Tikz nodes via two parallel arrows are not applicable.

First Approaches and description of MWE:

Here is a MWE with first approaches.

  1. Using the angle results in non-parallel lines for different sizes (if the angles are simply set to the same sizes).
  2. The bend left option also uses angles, but calculates them automatically.
  3. The approach with a fixed shift up and down with [yshift=...] requires manual effort and does not draw the arrows up to the nodes. In addition, there would be problems with this approach if the nodes were at an arbitrary angle to each other, as in 4.
  4. This is the desired result. However, the code was adjusted manually.

MWE:

enter image description here

\documentclass[border=3mm]{standalone}

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

\begin{document}

\begin{tikzpicture}[
    every node/.style={draw, circle},
    >=stealth',
]

    \node (a) {1};
    \node[right=of a] (b) {bbb};

    \draw[red] (a) -- (b);
    \draw[->] (a.20) -- (b.160);
    \draw[<-] (a.-20) -- (b.-160);

    \begin{scope}[yshift=-18mm]
        \node (a) {2};
        \node[right=of a, yshift=5mm] (b) {bbb};

        \draw[red] (a) -- (b);
        \draw[->] (a) to[bend left] (b);
        \draw[->] (b) to[bend left] (a);
    \end{scope}

    \begin{scope}[xshift=30mm]
        \node (a) {3};
        \node[right=of a] (b) {bbb};

        \draw[red] (a) -- (b);
        \draw[->] ([yshift=1mm]a.east) -- ([yshift=1mm]b.west);
        \draw[<-] ([yshift=-1mm]a.east) -- ([yshift=-1mm]b.west);
    \end{scope}

    \begin{scope}[xshift=30mm, yshift=-18mm]
        \node (a) {4};
        \node[right=of a, yshift=5mm] (b) {bbb};

        \draw[red] (a) -- (b);
        \draw[->] (a.30) -- (b.185);
        \draw[<-] (a.00) -- (b.205);
    \end{scope}
\end{tikzpicture}

\end{document}

Goal:

I would like to have an option move left=#1 (like bend left=#1) which gives a result as in part 4 of the above figure.

Below is a test example with differently arranged nodes of different sizes. The two lines which should draw the arrows are commented out.

Minimal test example:

enter image description here

\documentclass[border=3mm]{standalone}

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

\begin{document}

\begin{tikzpicture}[
    every node/.style={draw, circle},
    >=stealth',
]

    \foreach \d in {1,...,16} {
        \node (a\d) at ($(0,0)+(90-\d*22.5:25mm)$) {\footnotesize $a_{\d}$};
        \node[minimum size=10+\d mm] (b\d) at ($(0,0)+(90-\d*22.5:50mm)$) {\footnotesize $b_{\d}$};
        \draw[red] (a\d) to (b\d);

        % TODO:
        %\draw[blue] (a\d) to[move left=30] node{x} (b\d);
        %\draw[yellow] (b\d) to[move right=30] node{y} (a\d);
    }
\end{tikzpicture}

\end{document}
3

For circle nodes it is rather easy.

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{positioning}
\usetikzlibrary{arrows}
\usetikzlibrary{calc}
\tikzset{shifted path/.style args={from #1 to #2 by #3}{insert path={
let \p1=($(#1.east)-(#1.center)$),
\p2=($(#2.east)-(#2.center)$),\p3=($(#1.center)-(#2.center)$),
\n1={veclen(\x1,\y1)},\n2={veclen(\x2,\y2)},\n3={atan2(\y3,\x3)} in
(#1.{\n3+180+asin(#3/\n1)}) to (#2.{\n3-asin(#3/\n2)})
}}}
\begin{document}

\begin{tikzpicture}[
    every node/.style={draw, circle},
    >=stealth',
]

    \node (a) {1};
    \node[right=of a] (b) {bbb};

    \draw[red] (a) -- (b);
    \draw[blue,->,shifted path=from a to b by 3pt];
    \draw[blue,->,shifted path=from b to a by 3pt];

    \begin{scope}[yshift=-18mm]
        \node (a) {2};
        \node[right=of a, yshift=5mm] (b) {bbb};

        \draw[red] (a) -- (b);
        \draw[blue,bend left,->,shifted path=from a to b by 3pt];
        \draw[blue,bend left,->,shifted path=from b to a by 3pt];
    \end{scope}

    \begin{scope}[xshift=30mm]
        \node (a) {3};
        \node[right=of a] (b) {bbb};

        \draw[red] (a) -- (b);
        \draw[blue,->,shifted path=from a to b by 3pt];
        \draw[blue,->,shifted path=from b to a by 3pt];
    \end{scope}

    \begin{scope}[xshift=30mm, yshift=-18mm]
        \node (a) {4};
        \node[right=of a, yshift=5mm] (b) {bbb};

        \draw[red] (a) -- (b);
        \draw[blue,bend left,->,shifted path=from a to b by 3pt];
        \draw[blue,bend left,->,shifted path=from b to a by 3pt];
    \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

Or a version that supports edge labels. (I'm not a big fan of quotes.)

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{positioning}
\usetikzlibrary{arrows}
\usetikzlibrary{calc}
\tikzset{dexteritas/.cd,
shifted path label/.style={pos=0.5,draw=none,rectangle,auto,sloped}}
\tikzset{shifted path/.style args={from #1 to #2 by #3}{insert path={
let \p1=($(#1.east)-(#1.center)$),
\p2=($(#2.east)-(#2.center)$),\p3=($(#1.center)-(#2.center)$),
\n1={veclen(\x1,\y1)},\n2={veclen(\x2,\y2)},\n3={atan2(\y3,\x3)} in
(#1.{\n3+180+asin(#3/\n1)}) to 
(#2.{\n3-asin(#3/\n2)})
}}}
\tikzset{labeled shifted path/.style args={from #1 to #2 by #3 label #4}{insert path={
let \p1=($(#1.east)-(#1.center)$),
\p2=($(#2.east)-(#2.center)$),\p3=($(#1.center)-(#2.center)$),
\n1={veclen(\x1,\y1)},\n2={veclen(\x2,\y2)},\n3={atan2(\y3,\x3)} in
(#1.{\n3+180+asin(#3/\n1)}) to node[dexteritas/shifted path label]{#4}
(#2.{\n3-asin(#3/\n2)})
}}}

\makeatother
\begin{document}

\begin{tikzpicture}[
    every node/.style={draw, circle},
    >=stealth',
]

    \node (a) {1};
    \node[right=of a] (b) {bbb};

    \draw[red] (a) -- (b);
    \draw[blue,->,shifted path=from a to b by 3pt];
    \draw[blue,->,shifted path=from b to a by 3pt];

    \begin{scope}[yshift=-18mm]
        \node (a) {2};
        \node[right=of a, yshift=5mm] (b) {bbb};

        \draw[red] (a) -- (b);
        \draw[blue,bend left,->,shifted path=from a to b by 3pt];
        \draw[blue,bend left,->,shifted path=from b to a by 3pt];
    \end{scope}

    \begin{scope}[xshift=30mm]
        \node (a) {3};
        \node[right=of a] (b) {bbb};

        \draw[red] (a) -- (b);
        \draw[blue,->,shifted path=from a to b by 3pt];
        \draw[blue,->,shifted path=from b to a by 3pt];
    \end{scope}

    \begin{scope}[xshift=30mm, yshift=-18mm]
        \node (a) {4};
        \node[right=of a, yshift=5mm] (b) {bbb};

        \draw[red] (a) -- (b);
        \draw[blue,bend left,->,labeled shifted path=from a to b by 3pt label hi];
        \draw[blue,bend left,->,shifted path=from b to a by 3pt];
    \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

  • Thank you for your answer. It works great. Is it possible to give the new option to the to connection (as with the bend left option), i. e., \draw[blue,->] (a) to[shifted path=3pt] node{a} (b);? This way a node text could simply be written to the arrow. – dexteritas Apr 22 at 10:13
  • 1
    @dexteritas That's not too simple because \tikztostart and \tikztotarget, which are available in the to path construction, are coordinates, not nodes. So you lose a lot of information which you need to recover. – marmot Apr 22 at 13:31
  • 1
    @dexteritas I added a version that allows you to add edge labels. Of course one can change the syntax and/or make it more flexible. – marmot Apr 22 at 14:21

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.