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.

Transitioning from GraphViz to TikZ is hurting my brain...

My task is to generate flowcharts of the following variety:

image

In particular, I need a method to position nodes that share borders (preferably independent of their width and height) while adhering to a grid. Extra credit for explanations of how to draw brackets that indicate node grouping, as well as how to draw orthogonal arrows whose endpoints do not coincide (preferably without specifying exact coordinates or angles) or that align with specific columns, such as the load -> add arrow.

share|improve this question
    
thank you for the embed, @percusse –  bug Oct 2 '12 at 22:35
    
My pleasure. Welcome to TeX.SE –  percusse Oct 3 '12 at 0:29
add comment

1 Answer 1

up vote 12 down vote accepted

There were three main requests:

  1. A method to position nodes that share borders. One possibility here is to use the key node distance and the positioning library. An example:

    \documentclass{standalone}
    \usepackage{tikz}
    \usetikzlibrary{positioning}
    
    \begin{document}
    
    \begin{tikzpicture}[every node/.style={draw}]
    \node (a) {A};
    \node[right=of a] (b) {B};
    \node[right=of b] (c) {C};
    \begin{scope}[yshift=-1cm,node distance=-\pgflinewidth,every node/.append style={fill=blue!20}]
    \node (a) {A};
    \node[right=of a] (b) {B};
    \node[right=of b] (c) {C};
    \end{scope}
    \end{tikzpicture}
    
    \end{document}
    

    enter image description here

  2. How to draw orthogonal arrows whose endpoints do not coincide (preferably without specifying exact coordinates or angles) or that align with specific columns. The main tool here is the implicit syntax for the perpendicular coordinate system. The expression ( p |- q ) or ( q -| p ). For example, (0,1 |- 2,3) and (2,3 -| 0,1) both produce the same as (0,3); the following example shows this syntax in action:

    \documentclass{standalone}
    \usepackage{tikz}
    
    \begin{document}
    
    \begin{tikzpicture}
    \node at (0,0) (a) {A};
    \node at (2,2) (b) {B};
    \node at (4,-1) (c) {C};
    \node at (4,-2) (d) {D};
    
    \draw[red] (a) |- (b);
    \draw[blue] (a) -| (b);
    \draw[green] (c) -- (a|-c) -- (a|-d) -- (d);
    \end{tikzpicture}
    
    \end{document}
    

    enter image description here

  3. How to draw brackets that indicate node grouping. The idea here is to use decorations; particularly, the brace decoration offered by the decorations.pathreplacing library. A little example:

    \documentclass{standalone}
    \usepackage{tikz}
    \usetikzlibrary{decorations.pathreplacing}
    
    \begin{document}
    
    \begin{tikzpicture}
    \node (a) {A};
    \node at (2,2) (b) {B};
    \node at (4,0) (c) {C};
    \draw[decorate,decoration=brace] (a) -- (b);
    \draw[decorate,decoration=brace] (b) -- (c);
    \draw[decorate,decoration={brace,mirror}] (a) -- (c);
    \end{tikzpicture}
    
    \end{document}
    

    enter image description here

Combining these ideas and defining some styles for the nodes, the original diagram can be produced. The complete code:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc,positioning,arrows,decorations.pathreplacing}

\definecolor{myblue}{RGB}{170,223,249}
\begin{document}

\begin{tikzpicture}[
  >={stealth'},
  every node/.style={node distance=-\pgflinewidth},
  exx/.style={rectangle,draw,fill=gray!30,text width=0.9cm,align=center,font=\ttfamily},
  sblue/.style={rectangle,rounded corners,draw,fill=myblue,text width=1.25cm,
    align=center,text height=9pt,text depth=3pt,font=\sffamily},
  mtext/.style={text width=4cm,align=left,text height=9pt,text depth=3pt,font=\ttfamily}
]

% the upper eax,..., edx nodes
\node[exx] (eax) {\%eax};
\node[exx,right= of eax] (ebx) {\%ebx};
\node[exx,right= of ebx] (ecx) {\%ecx};
\node[exx,right= of ecx] (edx) {\%edx};

% the vertical blue nodes
\node[sblue,below right = 10pt of edx] (sadd) {s\_addr};
\node[sblue,below = of sadd] (sdata) {s\_data};
\node[sblue,below = of sdata] (load) {load};
\node[sblue,below = of load] (add) {add};
\node[sblue,below = of add] (sub) {sub};
\node[sblue,below = of sub] (jne) {jne};

% some vertical nodes to place text to the right of the blue nodes
\node[mtext,right = 20pt of sadd] (tsadd) {};
\node[mtext,below = of tsadd] (tsdata) {};
\node[mtext,below = -9pt of tsadd] {movl \%eax,(\%ecx)};
\node[mtext,right = 20pt of load] (tload) {movl (\%ebx),\%eax};
\node[mtext,below = of tload] (tadd) {addl \$1,\%eax};
\node[mtext,below = of tadd] (tsub) {subl \$1,\%edx};
\node[mtext,below = of tsub] (tjne) {jne loop};

% the lower eax,..., edx nodes
\node[exx,below left = 10pt of jne] (edx1) {\%edx};
\node[exx,left= of edx1] (ecx1) {\%ecx};
\node[exx,left= of ecx1] (ebx1) {\%ebx};
\node[exx,left= of ebx1] (eax1) {\%eax};

% the straight lines with arrow tips
\draw[->] (eax) |- (sdata);
\draw[->] (ebx) -- (ebx1);
\draw[->] (ecx) -- (ecx1);
\draw[->] (edx) |- (sub.170);
\draw[->] (sub.190) -| (edx1);
\draw[*->] (ecx|-sadd) |- (sadd);
\draw[*->] (ebx|-load.170) |- (load.170);
\draw[->] (load.190) -- (eax|-load.190) -- (eax|-add.170) -- (add.170);
\draw[->] (add.190) -| (eax1);

% the curved arrows
\draw[->] (sadd.355) to[out=-30,in=30] (sdata.5);
\draw[->] (sadd.0) to[out=-30,in=30] (load.350);
\draw[->,dashed] (sdata.355) to[out=-30,in=30] (load.5);
\draw[->] (sub.0) to[out=-30,in=30] (jne.0);

% the brace
\draw[decorate,decoration=brace] ( $(sadd.north)!.35!(tsadd.north) $ ) -- ( $(sdata.south)!.35!(tsdata.south) $ );

\end{tikzpicture}

\end{document}

enter image description here

share|improve this answer
    
This is all rather self explanatory, and finally clarifies the (|-) intersection syntax for me. Thanks. However, I had really hoped to avoid using bare angles and offsets such as sub.170 and below right = 20pt of edx, but I suppose I'm asking too much of TikZ. Every diagram I make seems to be a cycle of tiny tweaks ad nauseum...(as I noticed too in your edits) –  bug Oct 3 '12 at 0:31
    
Also, is it simple to overlap node borders (not creating a split node)? If not, I don't want to bother. –  bug Oct 3 '12 at 0:37
    
@bug setting node distance to 0pt (without the on grid option) you can make the borders overlap. –  Gonzalo Medina Oct 3 '12 at 0:42
    
I meant that the borders appear to be merely adjacent, giving the appearance of a border twice as thick. Is there a way to move the nodes closer by the width of one borderline? –  bug Oct 3 '12 at 0:52
    
@bug node distace=\pgflinewidth should work. –  Gonzalo Medina Oct 3 '12 at 0:53
show 2 more comments

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.