17

I'm producing some control theory flow sheets in TikZ where I have specified the node box size. Since I'm making a lot of these flow sheets, I have set global styles for them, for instance the box style I'm currently using:

box/.style={rectangle, draw, minimum width = 8ex,
            minimum height = 4ex, inner sep = 1ex}

The amount of text in the nodes varies. The problem is that if a node text is demanding more space than minimum, the rest of the nodes in that picture should keep the same size as the largest node. How can I do this? The solution in this question is one I would like to avoid, as it in my opinion is far too "manual", I need automation.

An MWE:

\documentclass[12pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\tikzset{
    box/.style={rectangle, draw, minimum width = 8ex,
                minimum height = 4ex, inner sep = 0},
    split/.style={circle, draw, minimum size = 2.5pt, fill=black,
                inner sep = 0},
}
\begin{document}
\begin{tikzpicture}[
    every path/.style={>={stealth}, ->, draw, node distance = 1pt, inner sep = 0pt},
    ]
    \node[split] (split)  {};
    \node[box] (I) at ($(split) + (4,0)$) {Short};
    \node[box] (P) at ($(I)+(0,1)$) {This node has long node text};
    \node[box] (D) at ($(I)+(0,-1)$) {Short};
    \draw (split.north) |-(P);
    \draw (split.east) -- (I) ;
    \draw (split.south) |-(D);

\end{tikzpicture}
\end{document}
8
  • I'm no expert, but it sounds like you would need several passes for that...
    – jub0bs
    Commented Apr 6, 2013 at 15:22
  • Or you have to measure the size of the largest text then use it in the minimum width declaration. Otherwise you have to read all nodes and then redraw which against automation idea.
    – percusse
    Commented Apr 6, 2013 at 15:24
  • See my solution to a related problem that is close to what percusse is suggesting.
    – jub0bs
    Commented Apr 6, 2013 at 15:30
  • I'll check later, but currently I'm thinking that you need fit library from tikz, I've answered about here some time ago. Maybe this helps.
    – m0nhawk
    Commented Apr 6, 2013 at 15:40
  • @Jubobs Do you mean that I should provide the node text first, measure it, set minimum width and then produce the node with the predefined node text?
    – Holene
    Commented Apr 6, 2013 at 16:02

1 Answer 1

27
+500

This answer was converted to its own TikZ library ext.node-families as part of my tikz-extensions package.


I think, this is nearly as automatic as it gets. It uses the .aux file and won't work when the picture is externalized with the external library.

You specify a family of nodes that shall have the same dimension with the following keys that are all in the name space /tikz/node family:

  1. Type: Text box.

    Before a node is constructed the dimension of the text box that contains the node's text (\pgfnodeparttextbox) is measured and compared. The biggest value is used.

    • text height=<name>: Nodes with the same <name> will have the same text height.

    • text depth=<name>: Nodes with the same <name> will have the same text depth.

    • text width=<name>: Nodes with the same <name> will have the same text width.

    • text width align = left|center|right:

      Setting the width of the text box only extends the box to the right. The content of th box needs to be re-aligned. The text width align key (default center) makes sure that is done correctly.

    • text=<name> sets all text height, text depth and text width to the same <name>.

    By default, this is only set up for the base shapes rectangle and circle. After another shape is declared (usually by loading one of the shapes.* libraries) it can be setup in the same way by using

    \tikzset{node family/setup shape=<shape name>}
    

    This should be done only once per shape.

    Since this only changes the dimensions of the text box, for different shapes in the same family this might lead to different widths or height of the shape since their dimensions are calculated different based on the size of the text box. Consider this example:

    \tikz[nodes=draw, node family/text width=test]
      \node {Foo} node[circle] {Barbarbar};
    

    which leads to the following output:

    enter image description here

  2. Type: Minimum height and minimum width.

    Contrary to the text box measurements, this uses the height and width of the shape that is calculated by the shape's declaration itself. As this calculation is done somewhere deep inside the shape's declaration new shape declarations are necessary: Circle and Rectangle.

    • width=<name>: Nodes with the same <name> will have the same width.

    • height=<name>: Nodes with the same <name> will have the same height.

    As with /pgf/minimum width and /pgf/minimum height, this ignores any values of /pgf/outer xsep and /pgf/outer ysep or the line width itself.

Setting <name> to an empty value will disable the actions of this library.


Internally, the writing to the .aux file happens at the end of the picture which uses \tikz@atend@picture (execute at end picture).

The key prefix specifies the prefix for all node families. By default this is \pgfpictureid-, this makes it so that node families only apply to TikZpictures indidvidually.

In the example below, all familes are named test but they are all different ones.


I have also used the positioning library which makes the effect more noticeable.

The code still may be optimized a bit as for the example below seven additional macros are defined by the .aux file. It might be better to save all values from one family in one macro?

Code

\documentclass[12pt,tikz]{standalone}
\usetikzlibrary{
  positioning,       % better positioning (right=of …)
  ext.node-families, % node families
  arrows.meta        % arrow tips
}
\begin{document}
\begin{tikzpicture}[
  node distance=.3cm and 1cm,
  box/.style={
    rectangle, draw, minimum width=+8ex, minimum height=+4ex, inner sep=+0pt,
    node family/text width=test},
  split/.style={
    circle, draw, minimum size=+2.5pt, fill=black, inner sep=+0pt}]
\node[split] (split)  {};
\node[box, right=of split] (I)  {Short};
\node[box, above=of I]     (P)  {This node has long node text};
\node[box, below=of I]     (D)  {Short};
\draw[-Stealth] (split.north) |-(P);
\draw[-Stealth] (split.east) -- (I) ;
\draw[-Stealth] (split.south) |-(D);
\end{tikzpicture}
\tikz % only the same height (text is still centered)
  \foreach \cnt[count=\Cnt] in {a,...,h}
    \node[draw, Circle, node family/height=test] at (right:\Cnt) {\cnt};
\tikz % height and text height (text depth set to zero)
  \foreach \cnt[count=\Cnt] in {a,...,h}
    \node[draw, Circle, text depth=+0pt,
      node family={height=test, text height=test}]
      at (right:\Cnt) {\cnt};
\begin{tikzpicture}[% http://tex.stackexchange.com/q/134983
   nodes={circle, draw=black, node family/text=test}]
\node                 (A) {$n$};
\node[right=0pt of A] (B) {$n+1$};
\end{tikzpicture}
\end{document}

Output

First compilation

enter image description here

Second compilation

enter image description here

Output (Examples)

enter image description here enter image description here enter image description here

0

You must log in to answer this question.

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