Drawing path diagrams with minimal effort?

I wonder how to draw such path diagrams with minimal effort.

-
Here's an answer with minimal effort: use TikZ. –  Matthew Leingang Aug 28 '11 at 23:12
I think there's an example very much along these lines in the TikZ manual, actually. –  hoyland Aug 28 '11 at 23:15
Maybe this looks a bit silly but could someone let me know how I can remove the tags V,E, etc in the output? I know how to write my own text but the V, E, etc come in the diagrams as a fixture. Thanks, –  Shahraz May 10 '13 at 15:34

Here is another solution using TiKZ, but without operating on a grid. [It has been edited somewhat to simplify the code, based on the comments.]

TiKZ is an awesome package for making diagrams. Because you do it programmatically rather than interactively, you can make images very precisely, and with higher-level concepts; but it involves some forethought if you want to do it quickly. I will describe the workflow, in order to describe not just what code would produce this image, but to indicate how you can go about designing code to produce this image.

Obligatory pre-amble

Use something like this at the beginning of your document.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc,shapes}

\begin{document}


The command \usetikzlibrary should always accompany \usepackage{tikz}, because there's always some library you're going to want to use. In our case, we want calc to compute relative positions, and shapes to get e.g. elliptical nodes. The excellent documentation for TiKZ and PGF will always let you know what libraries you need to put things in your picture.

Defining styles

Your picture has several nodes (boxes, ellipses) with common features. We define different styles of nodes which more-or-less duplicate them. You should name them more intelligently than I have. All of these are settings which describe how they ought to look. (The "inner sep" parameter defines how far the border must be from the text from the default; all of the values were achieved by trial and error.)

\tikzstyle{input}=[font=\scriptsize\sffamily\bfseries]
\tikzstyle{yelbox}=[rectangle,draw=black,fill=yellow,
font=\scriptsize\sffamily\bfseries,inner sep=6pt]
\tikzstyle{yelball}=[ellipse,draw=black,fill=yellow,
font=\scriptsize\sffamily\bfseries,inner sep=-1pt]
\tikzstyle{whiteball}=[ellipse,draw=black,fill=white,
font=\scriptsize\sffamily\bfseries,inner sep=-1pt]


There are also different kinds of arrows which are repeated: we define styles for those as well. (Here, "latex" is just the name of the triangular arrow-head; I would prefer to use "stealth" myself, but I'm duplicating your image in this case.)

\tikzstyle{arr}=[-latex,black,line width=1pt]
\tikzstyle{doublearr}=[latex-latex,black,line width=1pt]
\tikzstyle{bluearr}=[-latex,blue,line width=1pt]


Some of your nodes have features such as labels with multiple lines. We're going to make a macro to produce those labels nicely. The default width of 3em was achieved by trial-and-error.

\newcommand\nodelabel[3][3em]{\parbox{#1}{\centering #2 \\ #3 }}


In order to more quickly prototype the image, I want fast control over the spacing of the nodes vertically, which is where there is the most variation (and the most non-uniformity). I will define a scaling factor that I can adjust for this (set to a negative number, to change the normal TiKZ convention so that larger numbers correspond to larger distances downward).

\newcommand\vertspacing{-1.5}


Building the picture

Here we go:

\begin{tikzpicture}[scale=0.8]


The scale was found by trial-and-error to get it to fit on a single page. You can also independently control the x-scaling and y-scaling, but I didn't do it that way, because I wanted to reverse the directions for co-ordinates anyway, and could do the scaling another way. (You can do this with a negative y-scaling, but then it messes up with the corners of the nodes, such as .north and .south which I will use below.)

While you're building this, you should be re-compiling all the time to find out whether your placement is working well, and to adjust the styles of the nodes to make their appearance work better. But don't spend too much time making everything perfect; get things just almost-right first, and then make them perfect at the end.

Building the E nodes

These are the nodes with E labels on the left and right. We will give them names so that we can refer to the nodes when drawing arrows.

I eye-balled the relative vertical spacing of the nodes; wherever there was a larger gap, I settled on an incremental spacing of 0.3 or 0.4. The horizontal positions were also eye-balled (and tweaked slightly), using negative/positive values to ensure symmetry.

\foreach \label/\row in
{E16/1, E17/2.3, E14/3.3, E15/4.7, E18/5.7, E19/7}
\node [input] (\label) at ($(-7.5,\vertspacing*\row)$) {\label};

\foreach \label/\row in
{E10/1, E11/2.3, E8/3.3, E9/4.7, E12/5.7, E13/7}
\node [input] (\label) at ($(7.5,\vertspacing*\row)$) {\label};


The (\label) assigns the name of the node which we will use later; the {\label} tells what label the nodes should be printed with.

Building the V nodes

These are the nodes with V labels, which will be the names of the nodes. They also have separate titles, which are the Axxx#-style part of their printed labels. They have similar vertical positioning as the input nodes. We produce their labels using the \nodelabel macro we defined earlier.

\foreach \title/\label/\row in
{GSSC1/V16/1, GSCR1/V17/2.3, ASCC1/V14/3.3, ASCB1/V15/4.7, AAET1/V18/5.7, AAMA1/V19/7}
\node [yelbox] (\label) at ($(-5,\vertspacing*\row)$) {\nodelabel{\title}{\label}};

\foreach \title/\label/\row in
{GSSC2/V10/1, GSCR2/V11/2.3, ASCC2/V8/3.3, ASCB2/V9/4.7, AAET2/V12/5.7, AAMA2/V13/7}
\node [yelbox] (\label) at ($(5,\vertspacing*\row)$) {\nodelabel{\title}{\label}};


We use the V# part of the label to name the nodes, because it's shorter, and because they match up with the names of the neighboring E nodes; this will be convenient later.

Building the F nodes

These are the elliptical nodes with the F labels. This is again similar to the V nodes. Their vertical positioning is basically at the gaps of the V nodes; this was computed by hand, though if you were slightly fancier you could have TiKZ do it for you. The width of 3.5em is chosen to force the ellipse to have about the same shape as in the original diagram.

\foreach \title/\label/\row in
{GSC/F1/1.65/4, ASC/F2/4/4, AA/F3/6.35/4}
\node [whiteball] (\label) at ($(-2,\vertspacing*\row)$)
{\nodelabel[3.5em]{\title \\ I}{\label}};

\foreach \title/\label/\row in
{GSC/F4/1.65, ASC/F5/4, AA/F6/6.35}
\node [yelball] (\label) at ($(2,\vertspacing*\row)$)
{\nodelabel[3.5em]{\title \\ II}{\label}};


Building the D nodes

For each of the F nodes on the right-hand side, there is a D node above and to the right. We place a D node for each one at a fixed position relative to the corresponding F node.

\foreach \label/\parent/\row in
{D4/F4/.7, D5/F5/3, D6/F6/5.4}
\node [input] (\label) at ($(\parent) + (0.5,-1*\vertspacing)$) {\label};


If you were to end the picture here by adding \end{tikzpicture}\end{document}, it would look like this:

Arrow drawing

Here, we take advantage of the labelling scheme for the nodes. In this case, because the labels are fairly uniform throughout the diagram, we basically just need to say "connect each E node with the appropriate V node", and similarly for the D nodes to the F nodes (with the appropriate style of arrow).

\foreach \j in {16, 17, 14, 15, 18, 19, 10, 11, 8, 9, 12, 13}
\draw [bluearr] (E\j) to (V\j);

\foreach \j in {4, 5, 6}
\draw [bluearr] (D\j) to (F\j);


The V and F nodes don't have such a simple naming scheme, but that's okay; we just specify the full node names. Also, we would like the arrows to terminate precisely at the middle of the vertical sides of the boxes; we do this by specifying the "east" or "west" anchors for these nodes, as appropriate.

\foreach \F/\Va/\Vb in  {F1/V16/V17, F2/V14/V15, F3/V18/V19}
{ \draw [arr] (\F) to (\Va.east); \draw [arr] (\F) to (\Vb.east); }

\foreach \F/\Va/\Vb in  {F4/V10/V11, F5/V8/V9, F6/V12/V13}
{ \draw [arr] (\F) to (\Va.west); \draw [arr] (\F) to (\Vb.west); }


The most complicated arrow to do in the diagram is between F1 and F3; we want this arrow to be anchored precisely at the centre-right, and to curve. We can do this by specifying the "east" anchor, and by specifying the angles (relative to due east) that the arrow should arc from. The angles were chosen by eye-balling.

\draw [doublearr, out=-60, in=60] (F1.east) to (F3.east);


The other arrows are fairly simple, and use the techniques described thus far.

\draw [doublearr] (F1) to (F2);
\draw [doublearr] (F2) to (F3);
\draw [arr]       (F1) to (F5.north);
\draw [arr]       (F1) to (F6.north);
\draw [arr]       (F2) to (F4.west);
\draw [arr]       (F2) to (F6.west);
\draw [arr]       (F3) to (F4.south);
\draw [arr]       (F3) to (F5.south);


Finishing up

And that's it!

\end{tikzpicture}
\end{document}


The resulting figure:

It's a pretty faithful representation of the original, if I so say so myself; And I made it in one hour, starting from nothing but the original to go by — some of which was spent looking up forgotten bits of TiKZ as I went!

-
Excellent answer! Two comments: TikZ loads color automatically, so you don't have to manually include that package, and for the curved arrow you could also use \path (F1.east) edge [tofro,bend left] (F3.east);, which eliminates the need to manually find appropriate support coordinates. –  Jake Aug 29 '11 at 1:57
Thanks Jake; I've removed color to simplify the answer. I didn't know about bend left, that's cool. Also, I'm interested to learn that \path is more reliable in interoperation with anchors and directions than \draw is (neither bend left nor out=-60, in=+60 interoperate with using the anchor .east). Still, specifying a precise control will allow you to determine just how far left and the nature of the curve. –  Niel de Beaudrap Aug 29 '11 at 2:06
Hm, that's strange. For me, \draw [tofro] (F1.east) to [bend left] (F3.east); connects the east anchors of F1 and F3 as expected. The curvature of the curve can be specified using bend left=<angle>. –  Jake Aug 29 '11 at 2:12
Ah, I was trying to do it the same place I has [tofro], which works when I don't have the anchors. [out=-60, in=60] works with anchors as well, provided you put it in the middle of the path rather than at the beginning with the arrow type. How peculiar. Edited to add: I've now found it's because I was using -- rather than to! –  Niel de Beaudrap Aug 29 '11 at 2:21
@Neil de Beaudrap: Thanks a lot for nice answer. –  MYaseen208 Aug 29 '11 at 4:02

Look at the second tutorial in the TikZ manual: it's titeled "A Petri-Net For Hagen", if you work through the example you'll be able to do something like this with ease:

-