Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I want to draw the following diagram in TikZ:

tikz diagram

Currently I use the following code to do this:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{snakes,arrows,shapes}

\begin{document}

\begin{tikzpicture}[>=latex',node distance = 2cm]
 \node (S1) {$S_1$};
 \node [left of = S1] (S2) {$S_2$};
 \node [above of = S2,node distance=1.04cm] (A) {$A$}; 
 \node [above of = S1,node distance=1.04cm] (B) {$B$};

 \node [below of = S2,node distance=1.04cm] (C) {$C$};
 \node [below of = S1,node distance=1.04cm] (D) {$D$};

 \draw [->,thick] (S1) to[bend left=40] node {} (S2);
 \draw [->,thick] (S2) to[bend left=40] node {} (S1);

 \draw [->,thick] (A) to[bend right=40] node {} (B);
 \draw [->,thick] (D) to[bend right=40] node {} (C);

\end{tikzpicture}

\end{document}

However you will notice that I am using an absolute distance (1.04cm) to make sure that the curves intersect at the mid points. If I change the node distance, the absolute distance must be manually adjusted each time by trial and error. Is there anyway to draw such a diagram using TikZ without using the absolute distance so that when I change the node distance the curves adjust automatically?

share|improve this question

3 Answers 3

up vote 7 down vote accepted

You may try out following approach. Despite it also uses some magic constants, but having worked them out once (well, I did it for you :)), you don't need to alter them anymore. \coeffx and \coeffy are already gracefully set for you, it is left to adjust \nodedistancex and \nodedistancey as you wish.

\documentclass{minimal}

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

\def \coeffx{0.29}
\def \coeffy{0.91}
\def \nodedistancex{4cm}
\def \nodedistancey{1cm}
\def \offsetx{\nodedistancex*\coeffx}
\def \offsety{\nodedistancey*\coeffy}

\begin{document}

\begin{tikzpicture}[>=latex', node distance=\nodedistancey and \nodedistancex]
 \node (S1) {$S_1$};
 \node[left=of S1] (S2) {$S_2$};
 \node[above=of S2] (A) {$A$}; 
 \node[above=of S1] (B) {$B$};
 \node[below=of S2] (C) {$C$};
 \node[below=of S1] (D) {$D$};

 \draw[->,thick] (S1) .. controls +(-\offsetx,\offsety) and +(\offsetx,\offsety) .. (S2);
 \draw[->,thick] (S2) .. controls +(\offsetx,-\offsety) and +(-\offsetx,-\offsety) .. (S1);
 \draw[->,thick] (A) .. controls +(\offsetx,-\offsety) and +(-\offsetx,-\offsety) .. (B);
 \draw[->,thick] (D) .. controls +(-\offsetx,\offsety) and +(\offsetx,\offsety) .. (C);
\end{tikzpicture}

\end{document}

enter image description hereenter image description here

share|improve this answer

you can add a dot in the middle of the path between A and S1 then draw the two arcs by that point

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{snakes,arrows,shapes}

\begin{document}

\begin{tikzpicture}[>=latex',node distance = 2cm]
 \node (S1) {$S_1$};
 \node [left of = S1] (S2) {$S_2$};
 \node [above of = S2,node distance=1.5cm] (A) {$A$}; 
 \node [above of = S1,node distance=1.5cm] (B) {$B$};

 \node [below of = S2,node distance=1.3cm] (C) {$C$};
 \node [below of = S1,node distance=1.3cm] (D) {$D$};

\path(A) -- (S1)coordinate[pos=0.5](inter1);
\path(C) -- (S1)coordinate[pos=0.5](inter2);
 \draw [->,thick] (S1) to[out=135,in=0] (inter1) to [out=180,in=45] (S2);
 \draw [->,thick] (S2) to[out=-45,in=180] (inter2) to [out=0,in=-135] (S1);
 \draw [->,thick] (A) to[out=-45,in=180] (inter1) to [out=0,in=-135]  (B);
 \draw [->,thick] (D)  to[out=135,in=0] (inter2) to [out=180,in=45] (C);

\end{tikzpicture}

\end{document}

arcs

share|improve this answer

One solution is as follows. On purpose, I added rows to the diagram, so that you can see one of the benefits of the loops. The output is

diagram

The code is (I hope it is self-explanatory) :

\documentclass{minimal}

\usepackage{tikz}
\usetikzlibrary{matrix}
\usetikzlibrary{calc}

\begin{document}


\begin{tikzpicture}[>=latex']

\pgfmathsetmacro{\rows}{5}

\matrix[matrix of math nodes,column sep=2cm,row sep = 1cm] (m) {
A&B\\
S_2&S_1\\
C&D\\
S_4&S_3\\
E&F\\
};

\foreach \k in {1,...,\rows}{
    \coordinate (c\k) at ($(m-\k-1)!0.5!(m-\k-2)$);
}

\foreach \k [count=\kprev] in {2,...,\rows}{

    \ifodd \k
        \tikzset{dir/.style={<-}}
    \else
        \tikzset{dir/.style={->}}
    \fi

    \coordinate (c) at ($(c\kprev)!0.5!(c\k)$);
    \draw[dir] (m-\kprev-1) to[out=-45,in=180] (c) to[out=0,in=225] (m-\kprev-2);
    \draw[dir] (m-\k-1) to[out=45,in=180] (c) to[out=0,in=135] (m-\k-2);
}   

\end{tikzpicture}

\end{document}

Edit : fixed the code to correct for the arrows

share|improve this answer
    
Nice solution, Frederic! –  Dmitrii Volosnykh May 5 '11 at 3:32
    
I like this one. The point is that you know that you want the curves to intersect and you know where those intersections should be - indeed, it's easier for you to see that than it is for the computer! So you tell the computer exactly where to put the curves. –  Loop Space May 5 '11 at 6:59

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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