23

I just started using TikZ and try to get a process control drawn by TikZ. It looks wonderful, but I am a real beginner. I use the simple flow chart as base and came to this result:

current situation

I use shapes (blue nodes) and lines together with "fit" to draw the dashed container around "Resources" and "Sensors" (complete code below). I am not satisfied with this for four reasons:

  1. I'd like to place the left box in between of the two middle ones (see red rectangle)
  2. Drawing an arrow from "Processing" to "Planning" is drawn right in the middle through "Sensors" and "Resources". Also, the arrow pointing to the dashed container should just be inside the container, not pointing to the egde
  3. I'd like to label the dashed container (see small rectangle just below "Planning")
  4. See the code, but the spacing of the rectangle is now done with a minimum height and width, because without it, the fit is too tight. However, it's not a real scalable solution, so I need to adjust the width/height every time I want to fit a rectangle around several nodes

improved situation

This is my source code:

\tikzstyle{b} = [rectangle, draw, fill=blue!20, node distance=3cm, text width=6em, text centered, rounded corners, minimum height=4em, thick]
\tikzstyle{c} = [rectangle, draw, minimum height=15em, minimum width=10em, dashed]
\tikzstyle{l} = [draw, -latex',thick]

\begin{tikzpicture}[auto]
    \node [b] (planning) {Planning};
    \node [b, below of=planning] (resources) {Resources};
    \node [b, below of=resources] (sensors) {Sensors};
    \node [b, left of=resources, node distance=4cm] (information) {Information system};
    \node [b, below of=sensors] (processing) {Processing};

    \node[c,fit=(resources) (sensors)] (container) {};

    \path [l] (planning) -- (resources);
    \path [l] (resources) -- (sensors);
    \path [l] (sensors) -- (processing);

    \path [l] (information) |- (planning);
    \path [l] (information) |- (processing);
\end{tikzpicture}

Can someone point me in the right direction to solve my problems?

4
  • A complete code is useful in such situation. Feb 27, 2012 at 16:50
  • What am I missing? I captured the complete tikzpicture environment to draw the scheme. Please suggest what could be improved in this question. Feb 27, 2012 at 17:01
  • 1
    What @Altermundus means is a full compilable code such that if somebody decides to give it a go, they can simply copy and start working on your example without the need to add relevant packages and class commands.
    – percusse
    Feb 27, 2012 at 17:05
  • @percusse, thanks, I'll do that next time :) Feb 27, 2012 at 17:19

4 Answers 4

19

There's a good chance some more elegant solution will appear soon, but here goes:

  1. By using the calc library you can add node halfway between sensors and resources, and position information with relation to this. I actually used the corners of these, resources.south west and sensors.north west, and put the new node midway between these.

  2. One way is to use relative coordinates to first go a little right of processing, then up, left to planning. By using |-/-| you can access coordinates that lie on the intersection of the horizontal line from one node and vertical line from another. That way you can end the arrow directly above sensors.north east, for example.

    I first add a new node, lowerright while drawing the line from resources to planning. (lowerright |- container.east) is the point that lies on the vertical line from lowerright and the horizontal line from container.east. Similar for (container.east -| resources.south east).

  3. You can add a node above the top left corner of container.

  4. Add inner sep=<dimension> to the container node, instead of defining width and height. This sets the distance from the contents of the node to the edge of the node.

enter image description here

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fit,arrows,calc,positioning}

\begin{document}
\tikzstyle{b} = [rectangle, draw, fill=blue!20, node distance=3cm, text width=6em, text centered, rounded corners, minimum height=4em, thick]
\tikzstyle{c} = [rectangle, draw, inner sep=0.5cm, dashed]
\tikzstyle{l} = [draw, -latex',thick]

\begin{tikzpicture}[auto]
    \node [b] (planning) {Planning};
    \node [b, below=of planning] (resources) {Resources};
    \node [b, below=of resources] (sensors) {Sensors};
    \coordinate (RSmid) at ($(resources.south west)!0.5!(sensors.north west)$);
    \node [b, left=of RSmid, node distance=4cm] (information) {Information system};
    \node [b, below=of sensors] (processing) {Processing};

    \node [c,fit=(resources) (sensors)] (container) {};

    \path [l] (planning) -- (resources);
    \path [l] (resources) -- (sensors);
    \path [l] (sensors) -- (processing);

    \path [l] (information) |- (planning);
    \path [l] (information) |- (processing);
    
    \node at (container.north west) [above right] {Desc};
    
    \draw [l] (processing.east) -- ++(2,0) node(lowerright){} |- (planning.east);
    \draw [l] (lowerright |- container.east) -- (container.east -| resources.south east);
\end{tikzpicture}
\end{document}
1
  • Too fast for me ! \coordinate (RSmid) at ($(resources)!0.5!(sensors)$); is enough ! Perfect for the other parts. Feb 27, 2012 at 17:01
11

The problem with answers based on positioning is that very difficult to scale the picture. Here an answer with the possibility to scale the picture without modify the texts.

\documentclass{article}
\usepackage{tikz,fullpage}
\usetikzlibrary{arrows,calc,fit}

\begin{document}

\tikzstyle{b} = [rectangle, draw, fill=blue!20, text width=6em,
                 text centered, rounded corners, minimum height=4em, thick]
\tikzstyle{c} = [rectangle, draw, dashed]
\tikzstyle{l} = [draw, -latex',thick]  

\begin{tikzpicture}[auto,scale=1.25]
    \node [b]    (planning) {Planning};
    \node [b]    (resources)   at ([shift={(0,-3)}] planning) {Resources};
    \node [b]    (sensors)     at ([shift={(0,-6)}] planning) {Sensors};
    \coordinate  (RSmid)       at ($(resources)!0.5!(sensors)$);  
    \node [b]    (information) at ([shift={(-4,0)}] RSmid)    {Information system};
    \node [b]    (processing)  at ([shift={(0,-9)}] planning) {Processing};
    % here I need to use `transform shape` because I need to transform `inner sep` ,
    %  the node is empty, ouf !!!
     \node [c,transform shape,inner sep=0.5cm,fit=(resources) (sensors)] (container) {};

    \path [l] (planning)  -- (resources);
    \path [l] (resources) -- (sensors);
    \path [l] (sensors)   -- (processing);

    \path [l] (information) |- (planning);
    \path [l] (information) |- (processing);

    \node at (container.north west) [above right] {Desc};

    \draw [l] (processing.east) -- ++(2,0) node(lowerright){} |- (planning.east);
    \draw [l] (lowerright |- container.east) -- (container.east -| resources.south east);
\end{tikzpicture}
\end{document}
1
  • I just wanted to show the possibility with the full verbosity but shift={(...)} is surely the way to go.
    – percusse
    Feb 27, 2012 at 18:36
9

Is this what you are looking for? I have made the following changes:

  • First (minor), I am using the positioning library to place the nodes rather than the default right of = syntax, which the manual tells me is deprecated. Basically, you write right = of instead :)

  • Second (minor), I am using the syntax \tikzset{key/.style = } rather than \tikzstyle, since the manual also says this is deprecated (actually, I think it's not even in there anymore). It's good to get in the habit of using \tikzset and, by extension, pgfkeys, directly, and no more writing.

  • Enough lecturing. You actually have most of the elements already. I placed information left = of container to get it in the middle where you wanted it, and I created a fictitious coordinate called fit right to the right of container through which I could pass some piecewise-rectilinear paths. I also used "incremental coordinates" to get the arrow from fit right to move a desired distance left.

  • I fixed the spacing of your rectangle by creating some more fictitious coordinates (also using incremental coordinates, rather than the calc library) to stretch the corners to the desired distance. It is not totally automated, but it is right there in the code. An alternative solution would be to use outer sep on the nodes resources and sensors, which pushes their anchors away from their borders, but that also affects the placement of the arrows, so it's not useful here.

  • I did use outer sep to place the label, as well as some more relative positioning.

Just a comment: you should have given a full document in your example. I had to guess which tikz libraries you used.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{positioning,fit,arrows}

\tikzset{
 b/.style
  = {rectangle, draw, fill=blue!20, node distance=3cm, text width=6em,
     text centered, rounded corners, minimum height=4em, thick},
 c/.style
  = {rectangle, draw, dashed,inner sep = 0pt},
 l/.style
  = {draw, -latex',thick}
}

\begin{document}

\begin{tikzpicture}[auto]
    \node [b] (planning) {Planning};
    \node [b, below = of planning] (resources) {Resources};
    \node [b, below = of resources] (sensors) {Sensors};
    \node [b, below = of sensors] (processing) {Processing};

    \path
     (resources.north west) ++(-1cm,1cm) coordinate (resources fit)
     (sensors.south east)   ++(1cm,-1cm) coordinate (sensors fit)
    ;
    \node [c,fit=(resources fit) (sensors fit)] (container) {};
    \node [above left = 0pt of container, anchor = south, draw, outer sep = 6pt] (container label) {Resources and sensors};

    \node [b, left = 4cm of container] (information) {Information system};
    \coordinate [right = 4cm of container] (fit right) {};

    \path [l] (planning) -- (resources);
    \path [l] (resources) -- (sensors);
    \path [l] (sensors) -- (processing);

    \path [l] (information) |- (planning);
    \path [l] (information) |- (processing);

    \path [l] (processing) -| (fit right) |- (planning);
    \path [l] (fit right) -- ++(-4.5cm,0);
\end{tikzpicture}

\end{document}

enter image description here

4
  • Thanks for the answer. Like @torbjorn-t, you use the \coordinate and ++(-4.5cm,0) features to accomplish what I wanted. I'll head again into the manual as you point out there are some improvements to make in my code. Feb 27, 2012 at 17:18
  • 1
    @JurianSluiman If for some obscure reason you can't use fit library, you can also use \draw[dashed] ([xshift=-5mm,yshift=5mm]resources.north west) rectangle ([xshift=5mm,yshift=-5mm]sensors.south east); It just does the positioning relative to the given coordinate.
    – percusse
    Feb 27, 2012 at 17:35
  • @percusse why not shift={(...)} but in this case you don't have an anchors to place a label and you get strange result if you want to scale the picture. Feb 27, 2012 at 18:26
  • If you scale the picture with scale=2 the size of the figure decreases and the result is very strange, now with scale=.8 the size of figure increases ! Feb 27, 2012 at 18:29
0

enter image description here

It is definitely a late answer. Its reason is that the proposed solution follows closely the initial code:

  • it is based on the positioning library only by introducing two phantom nodes at the center and at the center-right of the flow chart
  • the node information is placed and the arrows on the right are drawn with respect to these phantom nodes
  • the label of the dash container is a label of the node container.

The code

\documentclass[11pt, margin=1cm]{standalone}

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

\begin{document}

\tikzstyle{b} = [rectangle, draw, fill=blue!20, node distance=3cm,
text width=6em, text centered, rounded corners, minimum height=4em, thick]
\tikzstyle{c} = [rectangle, draw, minimum height=15em,
minimum width=10em, dashed]
\tikzstyle{l} = [draw, -latex', thick]

\begin{tikzpicture}[auto, every label/.style={scale=.8}]
  \node[b] (planning) {Planning};
  \node[b, below of=planning] (resources) {Resources};
  \node[b, below of=resources] (sensors) {Sensors};
  \node[b, below of=sensors] (processing) {Processing};
  
  \path (resources.center) -- (sensors.center) node[pos=.5, minimum width=7em, anchor=center] (phantom-c) {} ;
  \node[right of=phantom-c, node distance=3cm, inner sep=0pt, outer sep=0pt] (phantom-r) {};
  \node[b, left of=phantom-c, node distance=4cm] (information) {Information system};
  
  \node[c, fit=(resources) (sensors), label={105:some label}] (container) {};
  
  \path[l] (planning) -- (resources);
  \path[l] (resources) -- (sensors);
  \path[l] (sensors) -- (processing);
  
  \path[l] (information) |- (planning);
  \path[l] (information) |- (processing);
  
  \path[l] (processing) -| (phantom-r) |- (planning);
  \path[l] (phantom-r) -- (phantom-c);
\end{tikzpicture}
  
\end{document}

You must log in to answer this question.

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