13

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.

1
  • My pleasure. Welcome to TeX.SE
    – percusse
    Commented Oct 3, 2012 at 0:29

1 Answer 1

13

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

7
  • 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
    Commented Oct 3, 2012 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
    Commented Oct 3, 2012 at 0:37
  • @bug setting node distance to 0pt (without the on grid option) you can make the borders overlap. Commented Oct 3, 2012 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
    Commented Oct 3, 2012 at 0:52
  • @bug node distace=\pgflinewidth should work. Commented Oct 3, 2012 at 0:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .