# Custom shapes in Process Flow Diagram with Tikz

I’m trying to draw a process flow diagram using tikz. I'm not an expert, expecially in working with custom nodes.

I saw some other questions about chemical process flow diagrams, but they were general and did not explain how to customize a node to obtain a piece of equipment.

This is what I did so far, using some examples I found:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{positioning}

\begin{document}

\tikzset{HeatEx/.style={draw=black,fill=white,thick,circle,minimum width=1cm}}

\tikzset{Tank/.style={draw=black,fill=white,thick,rectangle,rounded corners=20pt,minimum width=1.5cm,minimum height=3cm,text width=1.5cm,align=center}}

\tikzset{3Phase/.style={draw=black,fill=white,thick,rectangle,rounded corners=20pt,minimum width=4cm,minimum height=1.5cm,text width=4cm,align=center}}

\tikzset{Reactor/.style={draw=black,fill=white,ultra thick,rectangle,rounded corners=20pt,minimum width=1.5cm,minimum height=4cm,text width=1.5cm,align=center}}

\def\COOLER#1#2#3{\node[HeatEx,right=#1 of #2](#3){};
\draw[thick,-latex] (#3.south east) to[in=-20,out=160] (#3.north west);
}

\def\HEATER#1#2#3#4{\node[HeatEx,below right=#1 and #2 of #3](#4){};
\draw[thick,-latex] (#4.north east) to[in=20,out=200] (#4.south west);
}

\def\TANK#1#2#3#4{\node[Tank,right=#1 of #2](#3){#4};}

\def\ThreeSEP#1#2#3#4{\node[3Phase,right=#1 of #2](#3){#4};}

\def\REACTOR#1#2#3#4#5{\node[Reactor,below right=#1 and #2 of #3](#4){#5};}

\begin{tikzpicture}
\node (START) {Text};

\TANK{1cm}{START}{F1}{Text}

\node[below right=of F1] (W1) {Text};

\COOLER{1cm}{F1}{C1};

\REACTOR{1cm}{1cm}{C1}{R1}{Text};

\HEATER{1cm}{1cm}{R1}{H1};

\ThreeSEP{1cm}{H1}{S1}{Text};

%Arrows
\draw[thick,-latex] (START.east) to (F1.west);

\draw[thick,-latex] (F1.south) |- (W1);

\draw[thick,-latex] (F1.east) to (C1.west);

\draw[thick,-latex] (C1.east) -| (R1.north);

\draw[thick,-latex] (R1.south) |- (H1.west);

\draw[thick,-latex] (H1.east) to (S1.west);
\end{tikzpicture}
\end{document}


That produces:

I’m not able to get the shapes I want, basically because I don't know how to draw inside a node:

• the curved arrow inside the heat exchangers should go a little outside the circle;
• the three-phase separator (the horizontal vessel - \ThreeSEP) should be similar to the one in this picture, with the four ports shown:

I managed to draw the arrow inside the circle thanks to (#3.south east) to (#3.north west), but it would be (may be) simpler if I had “relative reference system” inside each node. Or, at least, something like (#3.south east+3mm,#3.south east+3mm) to (#3.north west+3mm,#3.north west+3mm) (if it even makes sense).

Another issue is the positioning of the nodes, that I control using several inputs and is not so easy to use; it would be easier if I could define the shape and then its relative position (at first I tried only with \tikset{} but I couldn't draw inside the node I defined). For example, I would like to have the first heat exchanger (\COOLER - C1) above right of the first vessel, but I should define a new style only to change below right to above right, or use the former with negative distances.

Finally, if there is a "smarter" way to do it, I am ready to change my code :-) .

Thanks to everyone!

The relative positioning (#3.south east+3mm,#3.south east+3mm) to (#3.north west+3mm,#3.north west+3mm) exists but your syntax is wrong. It should be like this for one coordinate:

($(#3.south east)+(3mm,3mm)$)


and so on. But I'd use only the horizontal shifting, since the vertical will make the arrow look weird.

Some notes:

• The \tikzset{} can group all settings without having to recall it each time. Also, if you repeat the same settings for many nodes, you can define a base style, basic in this case, and then use that for all the nodes that need it. So your tikzset won't be too overcrowded. Furthermore, you can override any setting in the basic style if you need (like ultra thick in your case for example). See code.
• The extra arrow in the \ThreeSEP command is a new parameter now, the #5 to be precise, which is the coordinate for the top of the arrow. If you can be more precise about the use you will make of it, I can improve it.

## Code

\documentclass[margin=10pt]{standalone}
\usepackage{tikz}

\usetikzlibrary{calc, positioning}

\tikzset{
basic/.style={draw=black,fill=white,thick,rectangle,rounded corners=20pt, align=center},
HeatEx/.style={draw=black,fill=white,thick,circle,minimum width=1cm},
Tank/.style={basic, minimum width=1.5cm,minimum height=3cm,text width=1.5cm},
3Phase/.style={basic, minimum width=4cm,minimum height=1.5cm,text width=4cm},
Reactor/.style={basic, ultra thick,minimum width=1.5cm,minimum height=4cm,text width=1.5cm},
}

\newcommand{\COOLER}[3]{
\node[HeatEx,right=#1 of #2](#3){};
\draw[thick,-latex] ($(#3.south east)+(3mm,0)$) to[out=170,in=-20] ($(#3.north west)+(-3mm,0)$);
}

\newcommand{\HEATER}[4]{
\node[HeatEx,below right=#1 and #2 of #3](#4){};
\draw[thick,-latex] ($(#4.north east)+(3mm,0)$) to[out=200,in=20] ($(#4.south west)+(-3mm,0)$);
}

\newcommand{\TANK}[4]{
\node[Tank,right=#1 of #2](#3){#4};
}

\newcommand{\ThreeSEP}[5]{
\node[3Phase,right=#1 of #2](#3){#4};
\draw[thick] (#3.south) to[out=-90,in=-90, looseness=2] node[midway] (sman) {} ($(#3.south)!.5!(#3.south east)$);
\draw[thick,->] (sman.center) --++ (0,-1cm) -- (#5);
}

\newcommand{\REACTOR}[5]{
\node[Reactor,below right=#1 and #2 of #3](#4){#5};
}

\begin{document}
\begin{tikzpicture}
\node (START) {Text};
\TANK{1cm}{START}{F1}{Text}
\node[below right=of F1] (W1) {Text};
\COOLER{1cm}{F1}{C1}
\REACTOR{1cm}{1cm}{C1}{R1}{Text}
\HEATER{1cm}{1cm}{R1}{H1}
\ThreeSEP{1cm}{H1}{S1}{Hello}{15,-12}

%Arrows
\draw[thick,-latex] (START.east) to (F1.west);
\draw[thick,-latex] (F1.south) |- (W1);
\draw[thick,-latex] (F1.east) to (C1.west);
\draw[thick,-latex] (C1.east) -| (R1.north);
\draw[thick,-latex] (R1.south) |- (H1.west);
\draw[thick,-latex] (H1.east) to (S1.west);
\end{tikzpicture}
\end{document}

• Thanks a lot! I didn't know many of the commands you used in your code, but it's clear and it's a very nice starting point! I will experiment a little with it :-)! – MarcoG Jun 16 '15 at 9:13
• @MarcoG Feel free to ask for clarifications if you don't understand something. :D – Alenanno Jun 16 '15 at 9:24
• I think I understood everything, but now I'm trying to draw inside the shapes; I can do it, but how can I remove everything that goes out of the edges ? Probably I'll have to use \clip, but I don't know how to set the area that has to be clipped. Thanks again! – MarcoG Jun 16 '15 at 9:47
• @MarcoG Add \clip (lower left x, lower left y) rectangle (upper right x, upper right y); where those are the coordinates, as in (-5,-5) rectangle (5,5);, but change them to your needs. Everything after this command will be clipped outside of those coordinates. So if you add this command at the beginning, everything will be clipped. At the end, nothing will be clipped. :) – Alenanno Jun 16 '15 at 10:13
• Thanks! I managed to clip a rectangle inside a shape using \clip ($(#4.west)!.(0.5)!(#4.south west)$) rectangle ($(#4.east)!.(0.5)!(#4.north east)$); in a scope environment. – MarcoG Jun 16 '15 at 10:37

You can get a better version of the cooler and heater by introducing an invisible outer circle, and drawing the curved line to the outside of it:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning}

\begin{document}

\tikzset{HeatEx/.style={draw=black,fill=white,thick,circle,minimum width=1cm}}

\def\COOLER#1#2#3{\node[HeatEx,right=#1 of #2](#3){};
\node (dummy) [circle, minimum width=1.4cm] at (#3.center) {};
\draw[thick,-latex] (dummy.south east) to[in=-20,out=160] (dummy.north west);
}

\begin{tikzpicture}
\node (START) {Start};
\COOLER{1cm}{START}{C1};
\draw[->, thick] (START) -- (C1.west);
\end{tikzpicture}

\end{document}


Which produces:

You will want to adjust the size of the dummy` circle according to how far you want the arrow to stick out of the circle.

• Thanks! In this way I won't need to worry about adding or substracting 2mm or whatever, but I only have to set the diameter of the circle! – MarcoG Jun 16 '15 at 9:14